home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / sd-26.zip / sd.c < prev    next >
C/C++ Source or Header  |  1992-09-09  |  89KB  |  2,411 lines

  1. /* SD -- square dance caller's helper.
  2.  
  3.     Copyright (C) 1990, 1991, 1992  William B. Ackerman.
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     This is for version 25. */
  20.  
  21. /* This defines the following function:
  22.    do_big_concept
  23.  
  24. and the following external variables:
  25.    global_tbonetest
  26.    global_livemask
  27.    global_selectmask
  28.    concept_table
  29. */
  30.  
  31. #include "sd.h"
  32.  
  33. int global_tbonetest;
  34. int global_livemask;
  35. int global_selectmask;
  36.  
  37.  
  38.  
  39. static void do_c1_phantom_move(
  40.    setup *ss,
  41.    parse_block *parseptr,
  42.    setup *result)
  43.  
  44. {
  45.    if (ss->kind == s_c1phan) {
  46.       setup setup1, setup2, res1;
  47.  
  48.       setup1 = *ss;
  49.       setup2 = *ss;
  50.       
  51.       setup1.kind = s2x4;
  52.       setup2.kind = s2x4;
  53.       setup1.rotation = ss->rotation;
  54.       setup2.rotation = ss->rotation+1;
  55.       (void) copy_person(&setup1, 0, ss, 0);
  56.       (void) copy_person(&setup1, 1, ss, 2);
  57.       (void) copy_person(&setup1, 2, ss, 7);
  58.       (void) copy_person(&setup1, 3, ss, 5);
  59.       (void) copy_person(&setup1, 4, ss, 8);
  60.       (void) copy_person(&setup1, 5, ss, 10);
  61.       (void) copy_person(&setup1, 6, ss, 15);
  62.       (void) copy_person(&setup1, 7, ss, 13);
  63.       (void) copy_rot(&setup2, 0, ss, 4, 033);
  64.       (void) copy_rot(&setup2, 1, ss, 6, 033);
  65.       (void) copy_rot(&setup2, 2, ss, 11, 033);
  66.       (void) copy_rot(&setup2, 3, ss, 9, 033);
  67.       (void) copy_rot(&setup2, 4, ss, 12, 033);
  68.       (void) copy_rot(&setup2, 5, ss, 14, 033);
  69.       (void) copy_rot(&setup2, 6, ss, 3, 033);
  70.       (void) copy_rot(&setup2, 7, ss, 1, 033);
  71.       
  72.       normalize_setup(&setup1, simple_normalize);
  73.       normalize_setup(&setup2, simple_normalize);
  74.       setup1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  75.       setup2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  76.       
  77.       move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  78.       move(&setup2, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  79.       result->setupflags |= res1.setupflags;
  80.       merge_setups(&res1, result);
  81.    }
  82.    else if (ss->kind == s4x4) {
  83.       if (global_livemask == 0x5C5C || global_livemask == 0xA3A3) {
  84.          /* Split into 4 vertical strips. */
  85.          divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  86.             &map_4x4v, phantest_ok, TRUE, result);
  87.       }
  88.       else if (global_livemask == 0xC5C5 || global_livemask == 0x3A3A) {
  89.          /* Split into 4 horizontal strips. */
  90.          divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  91.             (*map_lists[s1x4][3])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  92.       }
  93.       else
  94.          fail("Inappropriate setup for phantom concept.");
  95.  
  96.       if (result->kind == s2x8) {
  97.          setup temp;
  98.          
  99.          temp = *result;
  100.          clear_people(result);
  101.          
  102.          if (!(temp.people[0].id1 | temp.people[7].id1 | temp.people[8].id1 | temp.people[15].id1)) {
  103.             (void) copy_person(result, 0, &temp, 1);
  104.             (void) copy_person(result, 3, &temp, 6);
  105.             (void) copy_person(result, 4, &temp, 9);
  106.             (void) copy_person(result, 7, &temp, 14);
  107.          }
  108.          else if (!(temp.people[1].id1 | temp.people[6].id1 | temp.people[9].id1 | temp.people[14].id1)) {
  109.             (void) copy_person(result, 0, &temp, 0);
  110.             (void) copy_person(result, 3, &temp, 7);
  111.             (void) copy_person(result, 4, &temp, 8);
  112.             (void) copy_person(result, 7, &temp, 15);
  113.          }
  114.          else
  115.             fail("This call is not appropriate for use with phantom concept.");
  116.  
  117.          if (!(temp.people[2].id1 | temp.people[5].id1 | temp.people[10].id1 | temp.people[13].id1)) {
  118.             (void) copy_person(result, 1, &temp, 3);
  119.             (void) copy_person(result, 2, &temp, 4);
  120.             (void) copy_person(result, 5, &temp, 11);
  121.             (void) copy_person(result, 6, &temp, 12);
  122.          }
  123.          else if (!(temp.people[3].id1 | temp.people[4].id1 | temp.people[11].id1 | temp.people[12].id1)) {
  124.             (void) copy_person(result, 1, &temp, 2);
  125.             (void) copy_person(result, 2, &temp, 5);
  126.             (void) copy_person(result, 5, &temp, 10);
  127.             (void) copy_person(result, 6, &temp, 13);
  128.          }
  129.          else
  130.             fail("This call is not appropriate for use with phantom concept.");
  131.  
  132.          result->kind = s2x4;
  133.       }
  134.       else
  135.          fail("This call is not appropriate for use with phantom concept.");
  136.    }
  137.    else
  138.       fail("Inappropriate setup for phantom concept.");
  139. }
  140.  
  141.  
  142. static map_thing map_diag2a            = {{5, 7, 21, 15, 17, 19, 9, 3},   {0},                            {0}, {0}, MPKIND__NONE,        1,  s4x6,   s2x4,      1, 0};
  143. static map_thing map_diag2b            = {{2, 8, 22, 12, 14, 20, 10, 0},  {0},                            {0}, {0}, MPKIND__NONE,        1,  s4x6,   s2x4,      1, 0};
  144.  
  145.  
  146.  
  147.  
  148. typedef struct asdfgh {
  149.    int map[4];
  150.    int othermap[4];
  151.    struct asdfgh *other;
  152.    } diag_map;
  153.  
  154. /* These need to be external so that they can refer to each other. */
  155. extern diag_map map_diag1a;
  156. extern diag_map map_diag1b;
  157.  
  158. diag_map map_diag1a = {{8, 11, 0, 3}, {12, 15, 4, 7}, &map_diag1b};
  159. diag_map map_diag1b = {{12, 15, 4, 7}, {0, 3, 8, 11}, &map_diag1a};
  160.  
  161.  
  162. static void do_concept_single_diagonal(
  163.    setup *ss,
  164.    parse_block *parseptr,
  165.    setup *result)
  166.  
  167. {
  168.    int i;
  169.    int rot, tbonetest;
  170.    diag_map *map_ptr;
  171.    setup a1;
  172.    setup res1;
  173.  
  174.    tbonetest = global_tbonetest;
  175.  
  176.    if (!tbonetest) {
  177.       result->kind = nothing;
  178.       return;
  179.    }
  180.  
  181.    rot = (tbonetest ^ parseptr->concept->value.arg1 ^ 1) & 1;
  182.  
  183.    map_ptr = rot ? &map_diag1a : &map_diag1b;
  184.  
  185.    if      (global_selectmask == (global_livemask & 0x0909)) map_ptr = map_ptr->other;
  186.    else if (global_selectmask != (global_livemask & 0x9090))
  187.       tbonetest = -1;   /* Force error. */
  188.  
  189.    if (ss->kind != s4x4) tbonetest = -1;   /* Force error. */
  190.  
  191.    if ((tbonetest & 011) == 011) {
  192.       if (parseptr->concept->value.arg1 & 1)
  193.          fail("Designated people are not consistently in a diagonal line.");
  194.       else
  195.          fail("Designated people are not consistently in a diagonal column.");
  196.    }
  197.  
  198.    ss->rotation += rot;   /* Just flip the setup around and recanonicalize. */
  199.    canonicalize_rotation(ss);
  200.  
  201.    for (i=0; i<4; i++) {
  202.       (void) copy_person(&a1, i, ss, map_ptr->map[i]);
  203.       clear_person(ss, map_ptr->map[i]);
  204.    }
  205.  
  206.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  207.    a1.kind = s1x4;
  208.    a1.rotation = 0;
  209.    
  210.    update_id_bits(&a1);
  211.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  212.  
  213.    *result = *ss;
  214.  
  215.    if (res1.kind != s1x4)
  216.       fail("The call must go back to a 1x4.");
  217.  
  218.    /* The rotation is either 0 or 1. */
  219.    if (res1.rotation != 0) {
  220.       for (i=0; i<4; i++) {
  221.          install_rot(result, map_ptr->othermap[i], &res1, i, 011);
  222.       }
  223.    }
  224.    else {
  225.       for (i=0; i<4; i++) {
  226.          install_person(result, map_ptr->map[i], &res1, i);
  227.       }
  228.    }
  229.  
  230.    result->setupflags = res1.setupflags;
  231.    result->rotation -= rot;   /* Flip the setup back. */
  232. }
  233.  
  234.  
  235. static void do_concept_double_diagonal(
  236.    setup *ss,
  237.    parse_block *parseptr,
  238.    setup *result)
  239.  
  240. /* This concept is "standard", which means that it can look at global_tbonetest
  241.    and global_livemask, but may not look at anyone's facing direction other
  242.    than through global_tbonetest. */
  243.  
  244. {
  245.    int tbonetest;
  246.    map_thing *map_ptr;
  247.  
  248.    tbonetest = global_tbonetest;
  249.  
  250.    if      (global_livemask == 0x2A82A8) map_ptr = &map_diag2a;
  251.    else if (global_livemask == 0x505505) map_ptr = &map_diag2b;
  252.    else
  253.       tbonetest = -1;   /* Force error. */
  254.  
  255.    if (ss->kind != s4x6) tbonetest = -1;   /* Force error. */
  256.  
  257.    if (parseptr->concept->value.arg1 & 1) {
  258.       if (tbonetest & 010) fail("There are no diagonal lines here.");
  259.    }
  260.    else {
  261.       if (tbonetest & 1) fail("There are no diagonal columns here.");
  262.    }
  263.  
  264.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  265.       map_ptr, phantest_ok, TRUE, result);
  266. }
  267.  
  268.  
  269. static void do_concept_double_offset(
  270.    setup *ss,
  271.    parse_block *parseptr,
  272.    setup *result)
  273.  
  274. {
  275.    int top, bot, ctr;
  276.    map_thing *map_ptr;
  277.  
  278.    if (ss->kind != s2x4) fail("Must have a 2x4 setup to do this concept.");
  279.  
  280.    if (global_selectmask == (global_livemask & 0xCC)) {
  281.       top = ss->people[0].id1 | ss->people[1].id1;
  282.       bot = ss->people[4].id1 | ss->people[5].id1;
  283.       ctr = ss->people[2].id1 | ss->people[3].id1 | ss->people[6].id1 | ss->people[7].id1;
  284.       map_ptr = &map_dbloff1;
  285.    }
  286.    else if (global_selectmask == (global_livemask & 0x33)) {
  287.       top = ss->people[2].id1 | ss->people[3].id1;
  288.       bot = ss->people[6].id1 | ss->people[7].id1;
  289.       ctr = ss->people[0].id1 | ss->people[1].id1 | ss->people[4].id1 | ss->people[5].id1;
  290.       map_ptr = &map_dbloff2;
  291.    }
  292.    else
  293.       fail("The designated centers are improperly placed.");
  294.  
  295.    /* Check that the concept is correctly named. */
  296.  
  297.    switch (parseptr->concept->value.arg1) {
  298.       case 0:
  299.          /* Double-offset quarter tag */
  300.          /* **** need to check people more carefully -- need "signature". */
  301.          /* Need both tops = 012, both bots = 010. */
  302.          if ((ctr & 1) != 0)
  303.             fail("Facing directions are incorrect for this concept.");
  304.          break;
  305.       case 1:
  306.          /* Double-offset three-quarter tag */
  307.          /* **** need to check people more carefully -- need "signature". */
  308.          /* Need both tops = 010, both bots = 012. */
  309.          if ((ctr & 1) != 0)
  310.             fail("Facing directions are incorrect for this concept.");
  311.          break;
  312.       case 2:
  313.          /* Anything goes */
  314.          break;
  315.       case 3:
  316.          /* Double-offset diamonds */
  317.          if ((((top | bot) & 010) != 0) || ((ctr & 1) != 0))
  318.             fail("Facing directions are incorrect for this concept.");
  319.          break;
  320.    }
  321.  
  322.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  323.       map_ptr, phantest_ok, TRUE, result);
  324. }
  325.  
  326.  
  327.  
  328. static void do_concept_quad_lines(
  329.    setup *ss,
  330.    parse_block *parseptr,
  331.    setup *result)
  332.  
  333. /* This concept is "standard", which means that it can look at global_tbonetest
  334.    and global_livemask, but may not look at anyone's facing direction other
  335.    than through global_tbonetest. */
  336.  
  337. {
  338.    int rot;
  339.  
  340.    if (ss->kind != s4x4) fail("Must have a 4x4 setup to do this concept.");
  341.  
  342.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  343.  
  344.    rot = (global_tbonetest ^ parseptr->concept->value.arg1 ^ 1) & 1;
  345.    ss->rotation += rot;   /* Just flip the setup around and recanonicalize. */
  346.    canonicalize_rotation(ss);
  347.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  348.       (*map_lists[s1x4][3])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  349.    result->rotation -= rot;   /* Flip the setup back. */
  350. }
  351.  
  352.  
  353. static void do_concept_parallelogram(
  354.    setup *ss,
  355.    parse_block *parseptr,
  356.    setup *result)
  357.  
  358. {
  359.    map_thing *map_ptr;
  360.  
  361.    if (ss->kind == s2x6) {
  362.       if (global_livemask == 07474) map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_R_HALF][0];
  363.       else if (global_livemask == 01717) map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_L_HALF][0];
  364.       else fail("Can't find a parallelogram.");
  365.    }
  366.    else if (ss->kind == s2x8) {
  367.       warn(warn__full_pgram);
  368.       if (global_livemask == 0xF0F0) map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_R_FULL][0];
  369.       else if (global_livemask == 0x0F0F) map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_L_FULL][0];
  370.       else fail("Can't find a parallelogram.");
  371.    }
  372.    else
  373.       fail("Can't do parallelogram concept from this position.");
  374.  
  375.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  376.       map_ptr, phantest_ok, TRUE, result);
  377. }
  378.  
  379.  
  380. static void do_concept_quad_boxes_tog(
  381.    setup *ss,
  382.    parse_block *parseptr,
  383.    setup *result)
  384.  
  385. {
  386.    int cstuff, m1, m2, m3;
  387.  
  388.    if (ss->kind != s2x8) fail("Must have a 2x8 setup to do this concept.");
  389.    cstuff = parseptr->concept->value.arg1;
  390.  
  391.    /* cstuff =
  392.       forward  : 0
  393.       left     : 1
  394.       back     : 2
  395.       right    : 3
  396.       together : 8
  397.       apart    : 9 */
  398.  
  399.    if (cstuff < 4) {      /* Working forward/back/right/left. */
  400.       int tbonetest = ss->people[2].id1 |
  401.                       ss->people[3].id1 |
  402.                       ss->people[4].id1 |
  403.                       ss->people[5].id1 |
  404.                       ss->people[10].id1 |
  405.                       ss->people[11].id1 |
  406.                       ss->people[12].id1 |
  407.                       ss->people[13].id1;
  408.  
  409.       if ((tbonetest & 010) && (!(cstuff & 1))) fail("Must indicate left/right.");
  410.       if ((tbonetest & 01) && (cstuff & 1)) fail("Must indicate forward/back.");
  411.  
  412.       m1 = 0xC3 ; m2 = 0xC3; m3 = 0xFF;
  413.       cstuff <<= 2;
  414.  
  415.       /* Look at the center 8 people and put each one in the correct group. */
  416.  
  417.       if (((ss->people[2].id1  + 6) ^ cstuff) & 8) { m1 |= 0x04; m2 &= ~0x01; };
  418.       if (((ss->people[3].id1  + 6) ^ cstuff) & 8) { m1 |= 0x08; m2 &= ~0x02; };
  419.       if (((ss->people[4].id1  + 6) ^ cstuff) & 8) { m2 |= 0x04; m3 &= ~0x01; };
  420.       if (((ss->people[5].id1  + 6) ^ cstuff) & 8) { m2 |= 0x08; m3 &= ~0x02; };
  421.       if (((ss->people[10].id1 + 6) ^ cstuff) & 8) { m2 |= 0x10; m3 &= ~0x40; };
  422.       if (((ss->people[11].id1 + 6) ^ cstuff) & 8) { m2 |= 0x20; m3 &= ~0x80; };
  423.       if (((ss->people[12].id1 + 6) ^ cstuff) & 8) { m1 |= 0x10; m2 &= ~0x40; };
  424.       if (((ss->people[13].id1 + 6) ^ cstuff) & 8) { m1 |= 0x20; m2 &= ~0x80; };
  425.    }
  426.    else if (cstuff == 8) {      /* Working together. */
  427.       m1 = 0xE7 ; m2 = 0x66; m3 = 0x7E;
  428.    }
  429.    else {                       /* Working apart. */
  430.       m1 = 0xDB ; m2 = 0x99; m3 = 0xBD;
  431.    }
  432.  
  433.    overlapped_setup_move(ss, (*map_lists[s2x4][2])[MPKIND__OVERLAP][0], m1, m2, m3, parseptr->next, result);
  434. }
  435.  
  436.  
  437. static void do_concept_quad_lines_tog(
  438.    setup *ss,
  439.    parse_block *parseptr,
  440.    setup *result)
  441.  
  442. {
  443.    int i, tbonetest, cstuff;
  444.    int m1, m2, m3;
  445.    map_thing *map_ptr;
  446.  
  447.    cstuff = parseptr->concept->value.arg1;
  448.    /* cstuff =
  449.       forward  : 0
  450.       left     : 1
  451.       back     : 2
  452.       right    : 3
  453.       together : 8 (doesn't really exist)
  454.       apart    : 9 (doesn't really exist) */
  455.  
  456.    if (ss->kind != s4x4) fail("Must have a 4x4 setup to do this concept.");
  457.  
  458.    tbonetest = 0;
  459.    for (i=0; i<16; i++) tbonetest |= ss->people[i].id1;
  460.  
  461.    if ((tbonetest & 011) == 011) fail("Sorry, can't do this from T-bone setup.");
  462.  
  463.    m1 = 0xF0; m2 = 0xF0; m3 = 0xFF;
  464.  
  465.    map_ptr = ((cstuff ^ tbonetest) & 1) ? &map_ov_s2x4_k : (*map_lists[s2x4][2])[MPKIND__OVERLAP][1];
  466.  
  467.    /* Look at the center 8 people and put each one in the correct group. */
  468.  
  469.    if ((cstuff + 1 - ss->people[map_ptr->map2[0]].id1) & 2) { m2 |= 0x01; m3 &= ~0x80; };
  470.    if ((cstuff + 1 - ss->people[map_ptr->map2[1]].id1) & 2) { m2 |= 0x02; m3 &= ~0x40; };
  471.    if ((cstuff + 1 - ss->people[map_ptr->map2[2]].id1) & 2) { m2 |= 0x04; m3 &= ~0x20; };
  472.    if ((cstuff + 1 - ss->people[map_ptr->map2[3]].id1) & 2) { m2 |= 0x08; m3 &= ~0x10; };
  473.    if ((cstuff + 1 - ss->people[map_ptr->map2[4]].id1) & 2) { m1 |= 0x08; m2 &= ~0x10; };
  474.    if ((cstuff + 1 - ss->people[map_ptr->map2[5]].id1) & 2) { m1 |= 0x04; m2 &= ~0x20; };
  475.    if ((cstuff + 1 - ss->people[map_ptr->map2[6]].id1) & 2) { m1 |= 0x02; m2 &= ~0x40; };
  476.    if ((cstuff + 1 - ss->people[map_ptr->map2[7]].id1) & 2) { m1 |= 0x01; m2 &= ~0x80; };
  477.  
  478.    overlapped_setup_move(ss, map_ptr, m1, m2, m3, parseptr->next, result);
  479. }
  480.  
  481.  
  482. static void do_concept_triple_diamonds_tog(
  483.    setup *ss,
  484.    parse_block *parseptr,
  485.    setup *result)
  486.  
  487. {
  488.    int m1, m2;
  489.  
  490.    if (ss->kind != s_3dmd) fail("Must have a triple diamond setup to do this concept.");
  491.    if ((ss->people[1].id1 | ss->people[7].id1) & 010) fail("Can't tell where points of center diamond should work.");
  492.  
  493.    m1 = 0xE9; m2 = 0xBF;
  494.  
  495.    /* Look at the center diamond points and put each one in the correct group. */
  496.  
  497.    if (ss->people[1].id1 & 2) { m1 |= 0x02; m2 &= ~0x01; }
  498.    if (ss->people[7].id1 & 2) { m1 |= 0x10; m2 &= ~0x20; }
  499.  
  500.    overlapped_setup_move(ss, (*map_lists[s_qtag][1])[MPKIND__OVERLAP][0], m1, m2, 0, parseptr->next, result);
  501. }
  502.  
  503.  
  504.  
  505. static void do_concept_quad_diamonds_tog(
  506.    setup *ss,
  507.    parse_block *parseptr,
  508.    setup *result)
  509.  
  510. {
  511.    int m1, m2, m3;
  512.  
  513.    if (ss->kind != s_4dmd) fail("Must have a quadruple diamond setup to do this concept.");
  514.    if ((ss->people[1].id1 | ss->people[2].id1 | ss->people[9].id1 | ss->people[10].id1) & 010)
  515.       fail("Can't tell where points of center diamonds should work.");
  516.  
  517.    m1 = 0xE9; m2 = 0xA9; m3 = 0xBF;
  518.  
  519.    /* Look at the center diamond points and put each one in the correct group. */
  520.  
  521.    if (ss->people[1].id1 & 2) { m1 |= 0x02; m2 &= ~0x01; }
  522.    if (ss->people[2].id1 & 2) { m2 |= 0x02; m3 &= ~0x01; }
  523.    if (ss->people[9].id1 & 2) { m2 |= 0x10; m3 &= ~0x20; }
  524.    if (ss->people[10].id1 & 2) { m1 |= 0x10; m2 &= ~0x20; }
  525.  
  526.    overlapped_setup_move(ss, (*map_lists[s_qtag][2])[MPKIND__OVERLAP][0], m1, m2, m3, parseptr->next, result);
  527. }
  528.  
  529.  
  530.  
  531.  
  532. static void do_concept_triple_boxes_tog(
  533.    setup *ss,
  534.    parse_block *parseptr,
  535.    setup *result)
  536.  
  537. {
  538.    int cstuff;
  539.    int m1, m2;
  540.  
  541.    cstuff = parseptr->concept->value.arg1;
  542.    /* cstuff =
  543.       forward  : 0
  544.       left     : 1
  545.       back     : 2
  546.       right    : 3
  547.       together : 8
  548.       apart    : 9 */
  549.  
  550.    if (ss->kind != s2x6) fail("Must have a 2x6 setup to do this concept.");
  551.  
  552.    if (cstuff < 4) {         /* Working forward/back/right/left. */
  553.       int tbonetest = ss->people[2].id1 |
  554.                       ss->people[3].id1 |
  555.                       ss->people[8].id1 |
  556.                       ss->people[9].id1;
  557.  
  558.       if ((tbonetest & 010) && (!(cstuff & 1))) fail("Must indicate left/right.");
  559.       if ((tbonetest & 01) && (cstuff & 1)) fail("Must indicate forward/back.");
  560.  
  561.       /* Look at the center 4 people and put each one in the correct group. */
  562.  
  563.       m1 = 0xC3; m2 = 0xFF;
  564.       cstuff <<= 2;
  565.  
  566.       if (((ss->people[2].id1 + 6) ^ cstuff) & 8) { m1 |= 0x04 ; m2 &= ~0x01; };
  567.       if (((ss->people[3].id1 + 6) ^ cstuff) & 8) { m1 |= 0x08 ; m2 &= ~0x02; };
  568.       if (((ss->people[8].id1 + 6) ^ cstuff) & 8) { m1 |= 0x10 ; m2 &= ~0x40; };
  569.       if (((ss->people[9].id1 + 6) ^ cstuff) & 8) { m1 |= 0x20 ; m2 &= ~0x80; };
  570.    }
  571.    else if (cstuff == 8) {   /* Working together. */
  572.       m1 = 0xE7; m2 = 0x7E;
  573.    }
  574.    else {                    /* Working apart. */
  575.       m1 = 0xDB; m2 = 0xBD;
  576.    }
  577.  
  578.    overlapped_setup_move(ss, (*map_lists[s2x4][1])[MPKIND__OVERLAP][0], m1, m2, 0, parseptr->next, result);
  579. }
  580.  
  581.  
  582. static void do_concept_triple_lines(
  583.    setup *ss,
  584.    parse_block *parseptr,
  585.    setup *result)
  586.  
  587. /* This concept is "standard", which means that it can look at global_tbonetest
  588.    and global_livemask, but may not look at anyone's facing direction other
  589.    than through global_tbonetest. */
  590.  
  591. {
  592.    if (ss->kind != s3x4) fail("Must have a 3x4 setup for this concept.");
  593.  
  594.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  595.  
  596.    /* If this was triple columns, we allow stepping to a wave.  This makes it
  597.       possible to do interested cases of turn and weave, when one column
  598.       is a single 8 chain and another is a single DPT. */
  599.  
  600.    if (global_tbonetest & 010)
  601.       ss->setupflags |= SETUPFLAG__NO_STEP_TO_WAVE;
  602.  
  603.    if (!((parseptr->concept->value.arg1 ^ global_tbonetest) & 1)) {
  604.       if (global_tbonetest & 1) fail("There are no lines of 4 here.");
  605.       else                      fail("There are no columns of 4 here.");
  606.    }
  607.  
  608.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  609.       (*map_lists[s1x4][2])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  610. }
  611.  
  612.  
  613. static void do_concept_triple_lines_tog(
  614.    setup *ss,
  615.    parse_block *parseptr,
  616.    setup *result)
  617.  
  618. {
  619.    int cstuff, tbonetest;
  620.    int i, m1, m2, linesp;
  621.  
  622.    cstuff = parseptr->concept->value.arg1;
  623.    /* cstuff =
  624.       forward  : 0
  625.       left     : 1
  626.       back     : 2
  627.       right    : 3
  628.       together : 8 (doesn't really exist)
  629.       apart    : 9 (doesn't really exist) */
  630.  
  631.    linesp = parseptr->concept->value.arg2;
  632.  
  633.    if (!linesp && (!(cstuff & 1))) fail("Must indicate left/right.");
  634.    if (linesp && (cstuff & 1)) fail("Must indicate forward/back.");
  635.  
  636.    if (ss->kind != s3x4) fail("Must have a 3x4 setup for this concept.");
  637.  
  638.    tbonetest = 0;
  639.    for (i=0; i<12; i++) tbonetest |= ss->people[i].id1;
  640.  
  641.    if ((tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  642.  
  643.    /* If this was triple columns, we allow stepping to a wave.  This makes it
  644.       possible to do interested cases of turn and weave, when one column
  645.       is a single 8 chain and another is a single DPT. */
  646.  
  647.    /* ****** we should only permit it if "standard" was NOT used.  That is,
  648.       if "standard" was used, we should set SETUPFLAG__NO_STEP_TO_WAVE always. */
  649.  
  650.    if (tbonetest & 010)
  651.       ss->setupflags |= SETUPFLAG__NO_STEP_TO_WAVE;
  652.  
  653.    if (linesp) {
  654.       if (tbonetest & 1) fail("There are no lines of 4 here.");
  655.    }
  656.    else {
  657.       if (!(tbonetest & 1)) fail("There are no columns of 4 here.");
  658.    }
  659.  
  660.    /* Initially assign the centers to the upper (m2) group. */
  661.    m1 = 0xF0; m2 = 0xFF;
  662.  
  663.    /* Look at the center line people and put each one in the correct group. */
  664.  
  665.    if ((ss->people[10].id1 ^ cstuff) & 2) { m2 &= ~0x80 ; m1 |= 0x1; };
  666.    if ((ss->people[11].id1 ^ cstuff) & 2) { m2 &= ~0x40 ; m1 |= 0x2; };
  667.    if ((ss->people[5].id1  ^ cstuff) & 2) { m2 &= ~0x20 ; m1 |= 0x4; };
  668.    if ((ss->people[4].id1  ^ cstuff) & 2) { m2 &= ~0x10 ; m1 |= 0x8; };
  669.  
  670.    overlapped_setup_move(ss, (*map_lists[s2x4][1])[MPKIND__OVERLAP][1], m1, m2, 0, parseptr->next, result);
  671. }
  672.  
  673.  
  674.  
  675. static void do_concept_triple_diag(
  676.    setup *ss,
  677.    parse_block *parseptr,
  678.    setup *result)
  679.  
  680. /* This concept is "standard", which means that it can look at global_tbonetest
  681.    and global_livemask, but may not look at anyone's facing direction other
  682.    than through global_tbonetest. */
  683.  
  684. {
  685.    int q;
  686.  
  687.    if (ss->kind != s_bigblob) fail("Must have a rather large setup for this concept.");
  688.  
  689.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  690.  
  691.    if ((global_livemask & ~0x56A56A) == 0) q = 0;
  692.    else if ((global_livemask & ~0xA95A95) == 0) q = 2;
  693.    else fail("Can't identify triple diagonal setup.");
  694.  
  695.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  696.       maps_3diag[q + ((parseptr->concept->value.arg1 ^ global_tbonetest) & 1)],
  697.       phantest_ok, TRUE, result);
  698. }
  699.  
  700.  
  701.  
  702. static void do_concept_triple_diag_tog(
  703.    setup *ss,
  704.    parse_block *parseptr,
  705.    setup *result)
  706.  
  707. {
  708.    int cstuff, m1, m2, q;
  709.    map_thing *map_ptr;
  710.  
  711.    cstuff = parseptr->concept->value.arg1;
  712.    /* cstuff =
  713.       forward  : 0
  714.       left     : 1
  715.       back     : 2
  716.       right    : 3
  717.       together : 8 (doesn't really exist)
  718.       apart    : 9 (doesn't really exist) */
  719.  
  720.    if (ss->kind != s_bigblob) fail("Must have a rather large setup for this concept.");
  721.  
  722.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  723.  
  724.    /* Initially assign the centers to the right or upper (m2) group. */
  725.    m1 = 0xF0; m2 = 0xFF;
  726.  
  727.    if ((global_livemask & ~0x56A56A) == 0) q = 0;
  728.    else if ((global_livemask & ~0xA95A95) == 0) q = 2;
  729.    else fail("Can't identify triple diagonal setup.");
  730.  
  731.    /* Look at the center line/column people and put each one in the correct group. */
  732.  
  733.    map_ptr = maps_3diagwk[q+((cstuff ^ global_tbonetest) & 1)];
  734.  
  735.    if ((cstuff + 1 - ss->people[map_ptr->map1[0]].id1) & 2) { m2 &= ~0x80 ; m1 |= 0x1; };
  736.    if ((cstuff + 1 - ss->people[map_ptr->map1[1]].id1) & 2) { m2 &= ~0x40 ; m1 |= 0x2; };
  737.    if ((cstuff + 1 - ss->people[map_ptr->map1[2]].id1) & 2) { m2 &= ~0x20 ; m1 |= 0x4; };
  738.    if ((cstuff + 1 - ss->people[map_ptr->map1[3]].id1) & 2) { m2 &= ~0x10 ; m1 |= 0x8; };
  739.  
  740.    overlapped_setup_move(ss, map_ptr, m1, m2, 0, parseptr->next, result);
  741. }
  742.  
  743.  
  744.  
  745. static void do_concept_grand_working(
  746.    setup *ss,
  747.    parse_block *parseptr,
  748.    setup *result)
  749.  
  750. {
  751.    int cstuff, tbonetest;
  752.    int m1, m2, m3;
  753.    map_thing *the_map;
  754.  
  755.    cstuff = parseptr->concept->value.arg1;
  756.    /* cstuff =
  757.       forward  : 0
  758.       left     : 1
  759.       back     : 2
  760.       right    : 3
  761.       together : 8
  762.       apart    : 9 */
  763.  
  764.    if (cstuff < 4) {      /* Working forward/back/right/left. */
  765.       if (ss->kind != s2x4) fail("Must have a 2x4 setup for this concept.");
  766.  
  767.       tbonetest = ss->people[1].id1 | ss->people[2].id1 | ss->people[5].id1 | ss->people[6].id1;
  768.       if ((tbonetest & 010) && (!(cstuff & 1))) fail("Must indicate left/right.");
  769.       if ((tbonetest & 01) && (cstuff & 1)) fail("Must indicate forward/back.");
  770.  
  771.       /* Look at the center 4 people and put each one in the correct group. */
  772.  
  773.       m1 = 0x9; m2 = 0x9; m3 = 0xF;
  774.       cstuff <<= 2;
  775.  
  776.       if (((ss->people[1].id1 + 6) ^ cstuff) & 8) { m1 |= 0x2 ; m2 &= ~0x1; };
  777.       if (((ss->people[2].id1 + 6) ^ cstuff) & 8) { m2 |= 0x2 ; m3 &= ~0x1; };
  778.       if (((ss->people[5].id1 + 6) ^ cstuff) & 8) { m2 |= 0x4 ; m3 &= ~0x8; };
  779.       if (((ss->people[6].id1 + 6) ^ cstuff) & 8) { m1 |= 0x4 ; m2 &= ~0x8; };
  780.  
  781.       the_map = (*map_lists[s2x2][2])[MPKIND__OVERLAP][0];
  782.    }
  783.    else {      /* Working together or apart. */
  784.       if (ss->kind != s1x8) fail("May not specify together/apart here.");
  785.  
  786.       /* Put each of the center 4 people in the correct group, no need to look. */
  787.  
  788.       if (cstuff & 1) {
  789.          m1 = 0x7; m2 = 0x5; m3 = 0xD;
  790.       }
  791.       else {
  792.          m1 = 0xB; m2 = 0xA; m3 = 0xE;
  793.       }
  794.  
  795.       the_map = (*map_lists[s1x4][2])[MPKIND__OVERLAP][0];
  796.    }
  797.  
  798.    overlapped_setup_move(ss, the_map, m1, m2, m3, parseptr->next, result);
  799. }
  800.  
  801.  
  802. static void do_concept_do_phantom_2x2(
  803.    setup *ss,
  804.    parse_block *parseptr,
  805.    setup *result)
  806.  
  807. {
  808.    /* Do "blocks" or "4 phantom interlocked blocks" or "triangular blocks, etc. */
  809.  
  810.    if (ss->kind != s4x4) fail("Must have a 4x4 setup for this concept.");
  811.  
  812.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  813.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  814. }
  815.  
  816.  
  817. static void do_concept_do_phantom_boxes(
  818.    setup *ss,
  819.    parse_block *parseptr,
  820.    setup *result)
  821.  
  822. {
  823.    if (ss->kind != s2x8) fail("Must have a 2x8 setup for this concept.");
  824.  
  825.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  826.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  827. }
  828.  
  829.  
  830. static void do_concept_do_phantom_diamonds(
  831.    setup *ss,
  832.    parse_block *parseptr,
  833.    setup *result)
  834.  
  835. {
  836.    if (ss->kind != s_4dmd) fail("Must have a quadruple diamond setup for this concept.");
  837.  
  838.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  839.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  840. }
  841.  
  842.  
  843.  
  844. static void do_concept_do_phantom_2x3(
  845.    setup *ss,
  846.    parse_block *parseptr,
  847.    setup *result)
  848.  
  849. /* This concept is "standard", which means that it can look at global_tbonetest
  850.    and global_livemask, but may not look at anyone's facing direction other
  851.    than through global_tbonetest. */
  852.  
  853. {
  854.    if (ss->kind != s3x4) fail("Must have a 3x4 setup for this concept.");
  855.  
  856.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  857.  
  858.    if (((parseptr->concept->value.arg2 ^ global_tbonetest) & 1)) {
  859.       if (global_tbonetest & 1) fail("There are no 12-matrix columns here.");
  860.       else                      fail("There are no 12-matrix lines here.");
  861.    }
  862.  
  863.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  864.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  865. }
  866.  
  867.  
  868.  
  869. static void do_concept_divided_2x4(
  870.    setup *ss,
  871.    parse_block *parseptr,
  872.    setup *result)
  873.  
  874. /* This concept is "standard", which means that it can look at global_tbonetest
  875.    and global_livemask, but may not look at anyone's facing direction other
  876.    than through global_tbonetest. */
  877.  
  878. {
  879.    if (ss->kind != s2x8) fail("Must have a 2x8 setup for this concept.");
  880.  
  881.    if ((((parseptr->concept->value.arg2 ^ global_tbonetest) & 1) == 0) || ((global_tbonetest & 011) == 011)) {
  882.       if (parseptr->concept->value.arg2 & 1) fail("There are no divided lines here.");
  883.       else                                       fail("There are no divided columns here.");
  884.    }
  885.  
  886.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  887.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  888. }
  889.  
  890.  
  891.  
  892. static void do_concept_divided_2x3(
  893.    setup *ss,
  894.    parse_block *parseptr,
  895.    setup *result)
  896.  
  897. /* This concept is "standard", which means that it can look at global_tbonetest
  898.    and global_livemask, but may not look at anyone's facing direction other
  899.    than through global_tbonetest. */
  900.  
  901. {
  902.    if (ss->kind != s2x6) fail("Must have a 2x6 setup for this concept.");
  903.  
  904.    if ((((parseptr->concept->value.arg2 ^ global_tbonetest) & 1) == 0) || ((global_tbonetest & 011) == 011)) {
  905.       if (parseptr->concept->value.arg2 & 1) fail("There are no 12-matrix divided lines here.");
  906.       else                                       fail("There are no 12-matrix divided columns here.");
  907.    }
  908.  
  909.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  910.          parseptr->concept->value.maps, (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  911. }
  912.  
  913.  
  914.  
  915. static void do_concept_do_phantom_1x6(
  916.    setup *ss,
  917.    parse_block *parseptr,
  918.    setup *result)
  919.  
  920. /* This concept is "standard", which means that it can look at global_tbonetest
  921.    and global_livemask, but may not look at anyone's facing direction other
  922.    than through global_tbonetest. */
  923.  
  924. {
  925.    if (ss->kind != s2x6) fail("Must have a 2x6 setup for this concept.");
  926.  
  927.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  928.  
  929.    if (!((parseptr->concept->value.arg3 ^ global_tbonetest) & 1)) {
  930.       if (global_tbonetest & 1) fail("There are no lines of 6 here.");
  931.       else                      fail("There are no columns of 6 here.");
  932.    }
  933.  
  934.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  935.          (*map_lists[s_1x6][1])[MPKIND__SPLIT][1], (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  936. }
  937.  
  938.  
  939.  
  940. static void do_concept_do_phantom_1x8(
  941.    setup *ss,
  942.    parse_block *parseptr,
  943.    setup *result)
  944.  
  945. /* This concept is "standard", which means that it can look at global_tbonetest
  946.    and global_livemask, but may not look at anyone's facing direction other
  947.    than through global_tbonetest. */
  948.  
  949. {
  950.    if (ss->kind != s2x8) fail("Must have a 2x8 setup for this concept.");
  951.  
  952.    if ((global_tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  953.  
  954.    if (!((parseptr->concept->value.arg3 ^ global_tbonetest) & 1)) {
  955.       if (global_tbonetest & 1) fail("There are no grand lines here.");
  956.       else                      fail("There are no grand columns here.");
  957.    }
  958.  
  959.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  960.       (*map_lists[s1x8][1])[MPKIND__SPLIT][1], (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  961. }
  962.  
  963.  
  964.  
  965. static void do_concept_once_removed(
  966.    setup *ss,
  967.    parse_block *parseptr,
  968.    setup *result)
  969.  
  970. {
  971.    map_thing *the_map;
  972.    if (parseptr->concept->value.arg1) {
  973.       /* concept was "once removed diamonds" */
  974.       if (ss->kind == s_rigger) {
  975.          the_map = (*map_lists[sdmd][1])[MPKIND__REMOVED][0];
  976.       }
  977.       else {
  978.          fail("There are no once removed diamonds here.");
  979.       }
  980.    }
  981.    else {
  982.       /* concept was just "once removed" */
  983.       switch (ss->kind) {
  984.          case s2x4:
  985.             the_map = (*map_lists[s2x2][1])[MPKIND__REMOVED][0];
  986.             break;
  987.          case s1x8:
  988.             the_map = (*map_lists[s1x4][1])[MPKIND__REMOVED][0];
  989.             break;
  990.          case s1x4:
  991.             the_map = (*map_lists[s_1x2][1])[MPKIND__REMOVED][0];
  992.             break;
  993.          case s_rigger:
  994.             fail("You must select 'once removed diamonds' in this setup.");
  995.          default:
  996.             fail("Can't do 'once removed' from this setup.");
  997.       }
  998.    }
  999.  
  1000.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0, the_map, phantest_ok, TRUE, result);
  1001. }
  1002.  
  1003.  
  1004. static void do_concept_old_stretch(
  1005.    setup *ss,
  1006.    parse_block *parseptr,
  1007.    setup *result)
  1008.  
  1009. {
  1010.    move(ss, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1011.  
  1012.    if (result->kind == s2x4) {
  1013.       swap_people(result, 1, 2);
  1014.       swap_people(result, 5, 6);
  1015.    }
  1016.    else if (result->kind == s1x8) {
  1017.       swap_people(result, 3, 6);
  1018.       swap_people(result, 2, 7);
  1019.    }
  1020.    else
  1021.       fail("Old stretch call didn't go to 2x4 or 1x8 setup.");
  1022. }
  1023.  
  1024. static void do_concept_new_stretch(
  1025.    setup *ss,
  1026.    parse_block *parseptr,
  1027.    setup *result)
  1028.  
  1029. {
  1030.    setup tempsetup;
  1031.  
  1032.    tempsetup = *ss;
  1033.  
  1034.    if (tempsetup.kind == s2x4) {
  1035.       swap_people(&tempsetup, 1, 2);
  1036.       swap_people(&tempsetup, 5, 6);
  1037.    }
  1038.    else if (tempsetup.kind == s1x8) {
  1039.       swap_people(&tempsetup, 3, 6);
  1040.       swap_people(&tempsetup, 2, 7);
  1041.    }
  1042.    else
  1043.       fail("Stretched setup call didn't start in 2x4 or 1x8 setup.");
  1044.  
  1045.    tempsetup.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1046.    move(&tempsetup, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1047. }
  1048.  
  1049.  
  1050. static void do_concept_stable(
  1051.    setup *ss,
  1052.    parse_block *parseptr,
  1053.    setup *result)
  1054. {
  1055.    selector_kind saved_selector, new_selector;
  1056.    long_boolean everyone;
  1057.    int directions[8];
  1058.    int n, i, j, rot;
  1059.  
  1060.    everyone = !parseptr->concept->value.arg1;
  1061.    new_selector = parseptr->selector;
  1062.    n = setup_limits[ss->kind];
  1063.    if (n < 0) fail("Sorry, can't do stable starting in this setup.");
  1064.  
  1065.    for (i=0; i<=n; i++) {           /* Save current facing directions. */
  1066.       j = ss->people[i].id1;
  1067.       if (j & BIT_PERSON)
  1068.          directions[(j >> 6) & 07] = j & d_mask;
  1069.    }
  1070.  
  1071.    move(ss, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1072.    rot = ((ss->rotation - result->rotation) & 3) * 011;
  1073.  
  1074.    n = setup_limits[result->kind];
  1075.    if (n < 0) fail("Sorry, can't do stable going to this setup.");
  1076.  
  1077.    saved_selector = current_selector;
  1078.    current_selector = new_selector;
  1079.  
  1080.    for (i=0; i<=n; i++) {           /* Restore facing directions of selected people. */
  1081.       j = result->people[i].id1;
  1082.       if ((j & BIT_PERSON) && (everyone || selectp(result, i)))
  1083.          result->people[i].id1 = rotperson((j & (BIT_PERSON | ~d_mask)) | directions[(j >> 6) & 07], rot);
  1084.    }
  1085.  
  1086.    current_selector = saved_selector;
  1087. }
  1088.  
  1089.  
  1090. static void do_concept_checkerboard(
  1091.    setup *ss,
  1092.    parse_block *parseptr,
  1093.    setup *result)
  1094. {
  1095.    static int mape[16] = {0, 2, 4, 6, 1, 3, 5, 7};
  1096.    static int mapl[16] = {7, 1, 3, 5, 0, 6, 4, 2};
  1097.    static int mapb[16] = {1, 3, 5, 7, 0, 2, 4, 6};
  1098.    static int mapd[16] = {7, 1, 3, 5, 0, 2, 4, 6};
  1099.  
  1100.    int i, rot, offset;
  1101.    setup a1;
  1102.    setup res1;
  1103.    int *map_ptr;
  1104.  
  1105.    clear_people(result);
  1106.  
  1107.    if (ss->kind != s2x4) fail("Must have a 2x4 setup for 'checker' concept.");
  1108.  
  1109.    if ((ss->people[0].id1 & d_mask) == d_north && (ss->people[1].id1 & d_mask) != d_north &&
  1110.          (ss->people[2].id1 & d_mask) == d_north && (ss->people[3].id1 & d_mask) != d_north &&
  1111.          (ss->people[4].id1 & d_mask) == d_south && (ss->people[5].id1 & d_mask) != d_south &&
  1112.          (ss->people[6].id1 & d_mask) == d_south && (ss->people[7].id1 & d_mask) != d_south)
  1113.       offset = 0;
  1114.    else if ((ss->people[0].id1 & d_mask) != d_north && (ss->people[1].id1 & d_mask) == d_north &&
  1115.          (ss->people[2].id1 & d_mask) != d_north && (ss->people[3].id1 & d_mask) == d_north &&
  1116.          (ss->people[4].id1 & d_mask) != d_south && (ss->people[5].id1 & d_mask) == d_south &&
  1117.          (ss->people[6].id1 & d_mask) != d_south && (ss->people[7].id1 & d_mask) == d_south)
  1118.       offset = 4;
  1119.    else
  1120.       fail("Can't identify checkerboard people.");
  1121.  
  1122.    (void) copy_rot(result, mape[0+offset], ss, mape[1+offset], 022);
  1123.    (void) copy_rot(result, mape[1+offset], ss, mape[0+offset], 022);
  1124.    (void) copy_rot(result, mape[2+offset], ss, mape[3+offset], 022);
  1125.    (void) copy_rot(result, mape[3+offset], ss, mape[2+offset], 022);
  1126.  
  1127.    a1.kind = (setup_kind) parseptr->concept->value.arg1;
  1128.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1129.    a1.rotation = 0;
  1130.  
  1131.    switch (a1.kind) {
  1132.       case s1x4:
  1133.          map_ptr = mapl;
  1134.          break;
  1135.       case s2x2:
  1136.          map_ptr = mapb;
  1137.          break;
  1138.       case sdmd:
  1139.          map_ptr = mapd;
  1140.          break;
  1141.    }
  1142.  
  1143.    for (i=0; i<4; i++) (void) copy_person(&a1, i, ss, map_ptr[i+offset]);
  1144.  
  1145.    update_id_bits(&a1);
  1146.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  1147.  
  1148.    /* Look at the rotation coming out of the move.  If the setup is 1x4, we require it to be
  1149.       even (no checkerboard lockit allowed).  Otherwise, allow any rotation.  This means
  1150.       we allow diamonds that are oriented rather peculiarly! */
  1151.  
  1152.    if ((res1.rotation & 1) && res1.kind == s1x4)
  1153.       fail("'Checker' call went to 1x4 setup oriented wrong way.");
  1154.  
  1155.    rot = res1.rotation * 011;
  1156.  
  1157.    switch (res1.kind) {
  1158.       case s1x4:
  1159.          map_ptr = mapl;
  1160.          break;
  1161.       case s2x2:
  1162.          map_ptr = mapb;
  1163.          break;
  1164.       case sdmd:
  1165.          map_ptr = mapd;
  1166.          break;
  1167.       default:
  1168.          fail("Don't recognize ending setup after 'checker' call.");
  1169.    }
  1170.  
  1171.    for (i=0; i<4; i++) (void) copy_rot(result, map_ptr[i+offset], &res1, (i-res1.rotation)&3, rot);
  1172.    result->kind = s2x4;
  1173.    result->rotation = 0;
  1174.    result->setupflags = res1.setupflags;
  1175.    reinstate_rotation(ss, result);
  1176. }
  1177.  
  1178.  
  1179. static void do_concept_checkpoint(
  1180.    setup *ss,
  1181.    parse_block *parseptr,
  1182.    setup *result)
  1183.  
  1184. {
  1185.    if (parseptr->concept->value.arg1) {   /* 0 for normal, 1 for reverse checkpoint. */
  1186.       concentric_move(ss, parseptr->next, parseptr->subsidiary_root, NULLCALLSPEC, NULLCALLSPEC, 0, 0, schema_rev_checkpoint, 0, 0, result);
  1187.    }
  1188.    else {
  1189.       /* The "dfm_conc_force_otherway" flag forces Callerlab interpretation:
  1190.          If checkpointers go from 2x2 to 2x2, this is clear.
  1191.          If checkpointers go from 1x4 to 2x2, "dfm_conc_force_otherway" forces
  1192.             the Callerlab rule in preference to the "parallel_concentric_end" property
  1193.             on the call. */
  1194.       concentric_move(ss, parseptr->subsidiary_root, parseptr->next, NULLCALLSPEC, NULLCALLSPEC, 0, 0, schema_checkpoint, 0, dfm_conc_force_otherway, result);
  1195.    }
  1196. }
  1197.  
  1198.  
  1199.  
  1200. static void do_concept_sequential(
  1201.    setup *ss,
  1202.    parse_block *parseptr,
  1203.    setup *result)
  1204. {
  1205.    int finalsetupflags;
  1206.    int call_index;
  1207.    setup tempsetup;
  1208.    setup tttt;
  1209.    int current_elongation = ss->setupflags & SETUPFLAG__ELONGATE_MASK;
  1210.  
  1211.    finalsetupflags = 0;
  1212.    *result = *ss;
  1213.  
  1214.    for (call_index=0; call_index<2; call_index++) {
  1215.       tttt = *result;
  1216.       tttt.setupflags = (ss->setupflags & ~SETUPFLAG__ELONGATE_MASK) | current_elongation;
  1217.  
  1218.       if (call_index == 0)
  1219.          move(&tttt, parseptr->next, NULLCALLSPEC, 0, FALSE, &tempsetup);
  1220.       else
  1221.          move(&tttt, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &tempsetup);
  1222.  
  1223.       finalsetupflags |= tempsetup.setupflags;
  1224.  
  1225.       if (tempsetup.kind == s2x2) {
  1226.          switch (result->kind) {
  1227.             case s1x4: case sdmd: case s2x2:
  1228.                current_elongation = (((tempsetup.setupflags & RESULTFLAG__ELONGATE_MASK) / RESULTFLAG__ELONGATE_BIT) * SETUPFLAG__ELONGATE_BIT);
  1229.                break;
  1230.  
  1231.             /* Otherwise (perhaps the setup was a star) we have no idea how to elongate the setup. */
  1232.  
  1233.             default:
  1234.                current_elongation = 0;
  1235.                break;
  1236.          }
  1237.       }
  1238.       else
  1239.          current_elongation = 0;
  1240.  
  1241.       *result = tempsetup;
  1242.  
  1243.       /* Remove outboard phantoms. 
  1244.          It used to be that normalize_setup was not called
  1245.          here.  It was found that we couldn't do things like, from a suitable offset wave,
  1246.          [triple line 1/2 flip] back to a wave, that is, start offset and finish normally.
  1247.          So this has been added.  However, there may have been a reason for not normalizing.
  1248.          If any problems are found, it may be that a flag needs to be added to seqdef calls
  1249.          saying whether to remove outboard phantoms after each part. */
  1250.  
  1251.       normalize_setup(result, simple_normalize);
  1252.    }
  1253.  
  1254.    result->setupflags = (finalsetupflags & ~RESULTFLAG__ELONGATE_MASK) | ((current_elongation / SETUPFLAG__ELONGATE_BIT) * RESULTFLAG__ELONGATE_BIT);
  1255. }
  1256.  
  1257.  
  1258.  
  1259. static void do_concept_trace(
  1260.    setup *ss,
  1261.    parse_block *parseptr,
  1262.    setup *result)
  1263. {
  1264.    int r1, r2, r3, r4, rot1, rot2, rot3, rot4;
  1265.    int finalsetupflags;
  1266.    setup a1, a2, a3, a4, res1, res2, res3, res4, inners, outers;
  1267.  
  1268.    if (ss->kind != s_qtag) fail("Must have a 1/4-tag-like setup for trace.");
  1269.  
  1270.    clear_people(&a1);
  1271.    clear_people(&a2);
  1272.    clear_people(&a3);
  1273.    clear_people(&a4);
  1274.    clear_people(&inners);
  1275.    clear_people(&outers);
  1276.  
  1277.    finalsetupflags = 0;
  1278.  
  1279.    a1.kind = s2x2;
  1280.    a1.rotation = 0;
  1281.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1282.    a2.kind = s2x2;
  1283.    a2.rotation = 0;
  1284.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1285.    a3.kind = s2x2;
  1286.    a3.rotation = 0;
  1287.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1288.    a4.kind = s2x2;
  1289.    a4.rotation = 0;
  1290.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1291.  
  1292.    if ((ss->people[6].id1&d_mask) == d_north && (ss->people[2].id1&d_mask) == d_south) {
  1293.       (void) copy_person(&a1, 2, ss, 7);
  1294.       (void) copy_person(&a1, 3, ss, 6);
  1295.       a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1296.       move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  1297.       finalsetupflags |= res1.setupflags;
  1298.  
  1299.       (void) copy_person(&a2, 2, ss, 4);
  1300.       (void) copy_person(&a2, 3, ss, 5);
  1301.       a2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1302.       move(&a2, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &res2);
  1303.       finalsetupflags |= res2.setupflags;
  1304.  
  1305.       (void) copy_person(&a3, 0, ss, 3);
  1306.       (void) copy_person(&a3, 1, ss, 2);
  1307.       a3.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1308.       move(&a3, parseptr->next, NULLCALLSPEC, 0, FALSE, &res3);
  1309.       finalsetupflags |= res3.setupflags;
  1310.  
  1311.       (void) copy_person(&a4, 0, ss, 0);
  1312.       (void) copy_person(&a4, 1, ss, 1);
  1313.       a4.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1314.       move(&a4, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &res4);
  1315.       finalsetupflags |= res4.setupflags;
  1316.    }
  1317.    else if ((ss->people[6].id1&d_mask) == d_south && (ss->people[2].id1&d_mask) == d_north) {
  1318.       (void) copy_person(&a1, 0, ss, 0);
  1319.       (void) copy_person(&a1, 1, ss, 1);
  1320.       a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1321.       move(&a1, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &res1);
  1322.       finalsetupflags |= res1.setupflags;
  1323.  
  1324.       (void) copy_person(&a2, 0, ss, 6);
  1325.       (void) copy_person(&a2, 1, ss, 7);
  1326.       a2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1327.       move(&a2, parseptr->next, NULLCALLSPEC, 0, FALSE, &res2);
  1328.       finalsetupflags |= res2.setupflags;
  1329.  
  1330.       (void) copy_person(&a3, 2, ss, 4);
  1331.       (void) copy_person(&a3, 3, ss, 5);
  1332.       a3.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1333.       move(&a3, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &res3);
  1334.       finalsetupflags |= res3.setupflags;
  1335.  
  1336.       (void) copy_person(&a4, 2, ss, 2);
  1337.       (void) copy_person(&a4, 3, ss, 3);
  1338.       a4.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1339.       move(&a4, parseptr->next, NULLCALLSPEC, 0, FALSE, &res4);
  1340.       finalsetupflags |= res4.setupflags;
  1341.    }
  1342.    else
  1343.       fail("Can't determine which box people should work in.");
  1344.  
  1345.    /* Check that everyone is in a 2x2 or vertically oriented 1x4. */
  1346.  
  1347.    if      ((res1.kind != s2x2 && res1.kind != nothing && (res1.kind != s1x4 || (!(res1.rotation&1)))) ||
  1348.             (res2.kind != s2x2 && res2.kind != nothing && (res2.kind != s1x4 || (!(res2.rotation&1)))) ||
  1349.             (res3.kind != s2x2 && res3.kind != nothing && (res3.kind != s1x4 || (!(res3.rotation&1)))) ||
  1350.             (res4.kind != s2x2 && res4.kind != nothing && (res4.kind != s1x4 || (!(res4.rotation&1)))))
  1351.       fail("You can't do this.");
  1352.  
  1353.    /* Process people going into the center. */
  1354.  
  1355.    inners.rotation = 0;
  1356.  
  1357.    if   ((res1.kind == s2x2 && (res1.people[2].id1 | res1.people[3].id1)) ||
  1358.          (res2.kind == s2x2 && (res2.people[0].id1 | res2.people[1].id1)) ||
  1359.          (res3.kind == s2x2 && (res3.people[0].id1 | res3.people[1].id1)) ||
  1360.          (res4.kind == s2x2 && (res4.people[2].id1 | res4.people[3].id1)))
  1361.       inners.kind = s1x4;
  1362.    else
  1363.       inners.kind = nothing;
  1364.  
  1365.    r1 = res1.rotation & 2;
  1366.    rot1 = (res1.rotation & 3) * 011;
  1367.    r2 = res2.rotation & 2;
  1368.    rot2 = (res2.rotation & 3) * 011;
  1369.    r3 = res3.rotation & 2;
  1370.    rot3 = (res3.rotation & 3) * 011;
  1371.    r4 = res4.rotation & 2;
  1372.    rot4 = (res4.rotation & 3) * 011;
  1373.  
  1374.    if   ((res1.kind == s1x4 && (res1.people[2 ^ r1].id1 | res1.people[3 ^ r1].id1)) ||
  1375.          (res2.kind == s1x4 && (res2.people[0 ^ r2].id1 | res2.people[1 ^ r2].id1)) ||
  1376.          (res3.kind == s1x4 && (res3.people[0 ^ r3].id1 | res3.people[1 ^ r3].id1)) ||
  1377.          (res4.kind == s1x4 && (res4.people[2 ^ r4].id1 | res4.people[3 ^ r4].id1))) {
  1378.       if (inners.kind != nothing) fail("You can't do this.");
  1379.       inners.kind = s2x2;
  1380.    }
  1381.  
  1382.    if (res1.kind == s2x2) {
  1383.       install_person(&inners, 1, &res1, 2);
  1384.       install_person(&inners, 0, &res1, 3);
  1385.    }
  1386.    else {
  1387.       install_rot(&inners, 3, &res1, 2^r1, rot1);
  1388.       install_rot(&inners, 0, &res1, 3^r1, rot1);
  1389.    }
  1390.  
  1391.    if (res2.kind == s2x2) {
  1392.       install_person(&inners, 0, &res2, 0);
  1393.       install_person(&inners, 1, &res2, 1);
  1394.    }
  1395.    else {
  1396.       install_rot(&inners, 0, &res2, 0^r2, rot2);
  1397.       install_rot(&inners, 3, &res2, 1^r2, rot2);
  1398.    }
  1399.  
  1400.    if (res3.kind == s2x2) {
  1401.       install_person(&inners, 3, &res3, 0);
  1402.       install_person(&inners, 2, &res3, 1);
  1403.    }
  1404.    else {
  1405.       install_rot(&inners, 1, &res3, 0^r3, rot3);
  1406.       install_rot(&inners, 2, &res3, 1^r3, rot3);
  1407.    }
  1408.  
  1409.    if (res4.kind == s2x2) {
  1410.       install_person(&inners, 2, &res4, 2);
  1411.       install_person(&inners, 3, &res4, 3);
  1412.    }
  1413.    else {
  1414.       install_rot(&inners, 2, &res4, 2^r4, rot4);
  1415.       install_rot(&inners, 1, &res4, 3^r4, rot4);
  1416.    }
  1417.  
  1418.    /* Process people going to the outside. */
  1419.  
  1420.    outers.rotation = 0;
  1421.  
  1422.    if   ((res1.kind == s2x2 && (res1.people[0].id1 | res1.people[1].id1)) ||
  1423.          (res2.kind == s2x2 && (res2.people[2].id1 | res2.people[3].id1)) ||
  1424.          (res3.kind == s2x2 && (res3.people[2].id1 | res3.people[3].id1)) ||
  1425.          (res4.kind == s2x2 && (res4.people[0].id1 | res4.people[1].id1)))
  1426.       outers.kind = s2x2;
  1427.    else
  1428.       outers.kind = nothing;
  1429.  
  1430.    r1 = res1.rotation & 2;
  1431.    r2 = res2.rotation & 2;
  1432.    r3 = res3.rotation & 2;
  1433.    r4 = res4.rotation & 2;
  1434.  
  1435.    if   ((res1.kind == s1x4 && (res1.people[0 ^ r1].id1 | res1.people[1 ^ r1].id1)) ||
  1436.          (res2.kind == s1x4 && (res2.people[2 ^ r2].id1 | res2.people[3 ^ r2].id1)) ||
  1437.          (res3.kind == s1x4 && (res3.people[2 ^ r3].id1 | res3.people[3 ^ r3].id1)) ||
  1438.          (res4.kind == s1x4 && (res4.people[0 ^ r4].id1 | res4.people[1 ^ r4].id1))) {
  1439.       if (outers.kind != nothing) fail("You can't do this.");
  1440.       outers.kind = s1x4;
  1441.       outers.rotation = 1;
  1442.    }
  1443.  
  1444.    if (res1.kind == s2x2) {
  1445.       install_person(&outers, 0, &res1, 0);
  1446.       install_person(&outers, 1, &res1, 1);
  1447.    }
  1448.    else {
  1449.       install_rot(&outers, 0, &res1, 0 ^ (res1.rotation&2), ((res1.rotation-1)&3)*011);
  1450.       install_rot(&outers, 1, &res1, 1 ^ (res1.rotation&2), ((res1.rotation-1)&3)*011);
  1451.    }
  1452.  
  1453.    if (res2.kind == s2x2) {
  1454.       install_person(&outers, 2, &res2, 2);
  1455.       install_person(&outers, 3, &res2, 3);
  1456.    }
  1457.    else {
  1458.       install_rot(&outers, 2, &res2, 2 ^ (res2.rotation&2), ((res2.rotation-1)&3)*011);
  1459.       install_rot(&outers, 3, &res2, 3 ^ (res2.rotation&2), ((res2.rotation-1)&3)*011);
  1460.    }
  1461.  
  1462.    if (res3.kind == s2x2) {
  1463.       install_person(&outers, 2, &res3, 2);
  1464.       install_person(&outers, 3, &res3, 3);
  1465.    }
  1466.    else {
  1467.       install_rot(&outers, 2, &res3, 2 ^ (res3.rotation&2), ((res3.rotation-1)&3)*011);
  1468.       install_rot(&outers, 3, &res3, 3 ^ (res3.rotation&2), ((res3.rotation-1)&3)*011);
  1469.    }
  1470.  
  1471.    if (res4.kind == s2x2) {
  1472.       install_person(&outers, 0, &res4, 0);
  1473.       install_person(&outers, 1, &res4, 1);
  1474.    }
  1475.    else {
  1476.       install_rot(&outers, 0, &res4, 0 ^ (res4.rotation&2), ((res4.rotation-1)&3)*011);
  1477.       install_rot(&outers, 1, &res4, 1 ^ (res4.rotation&2), ((res4.rotation-1)&3)*011);
  1478.    }
  1479.  
  1480.    normalize_concentric(schema_concentric, 1, &inners, &outers, outers.rotation ^ 1, result);
  1481.    result->setupflags = finalsetupflags;
  1482.    reinstate_rotation(ss, result);
  1483. }
  1484.  
  1485.  
  1486.  
  1487. static void do_concept_quad_boxes(
  1488.    setup *ss,
  1489.    parse_block *parseptr,
  1490.    setup *result)
  1491. {
  1492.    if (ss->kind != s2x8) fail("Must have a 2x8 setup for this concept.");
  1493.  
  1494.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  1495.       (*map_lists[s2x2][3])[MPKIND__SPLIT][0], phantest_ok, TRUE, result);
  1496. }
  1497.  
  1498.  
  1499.  
  1500. static void do_concept_do_both_boxes(
  1501.    setup *ss,
  1502.    parse_block *parseptr,
  1503.    setup *result)
  1504. {
  1505.    if (ss->kind == s2x4) {
  1506.       divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  1507.          parseptr->concept->value.maps, phantest_ok, TRUE, result);
  1508.    }
  1509.    else if (ss->kind == s3x4 && parseptr->concept->value.arg2) {
  1510.       /* distorted_2x2s_move will notice that concept is funny and will do the right thing. */
  1511.       distorted_2x2s_move(ss, parseptr, result);
  1512.       reinstate_rotation(ss, result);
  1513.    }
  1514.    else
  1515.       fail("Need a 2x4 setup to do this concept.");
  1516. }
  1517.  
  1518.  
  1519. static void do_concept_triple_boxes(
  1520.    setup *ss,
  1521.    parse_block *parseptr,
  1522.    setup *result)
  1523. {
  1524.    if (ss->kind == s2x6) {
  1525.       divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  1526.             (*map_lists[s2x2][2])[MPKIND__SPLIT][0], phantest_ok, TRUE, result);
  1527.    }
  1528.    else
  1529.       fail("Need a 2x6 setup to do this concept.");
  1530. }
  1531.  
  1532.  
  1533. static void do_concept_centers_or_ends(
  1534.    setup *ss,
  1535.    parse_block *parseptr,
  1536.    setup *result)
  1537. {
  1538.    calldef_schema schema;
  1539.    int k = parseptr->concept->value.arg1;
  1540.  
  1541.    switch (k&6) {
  1542.       case 0:
  1543.          schema = schema_concentric;
  1544.          break;
  1545.       case 2:
  1546.          schema = schema_concentric_6_2;
  1547.          break;
  1548.       default:
  1549.          schema = schema_concentric_2_6;
  1550.          break;
  1551.    }
  1552.  
  1553.    if (k&1)
  1554.       concentric_move(ss, (parse_block *) 0, parseptr->next, NULLCALLSPEC, NULLCALLSPEC, 0, 0,
  1555.                schema, 0, 0, result);
  1556.    else
  1557.       concentric_move(ss, parseptr->next, (parse_block *) 0, NULLCALLSPEC, NULLCALLSPEC, 0, 0,
  1558.                schema, 0, 0, result);
  1559. }
  1560.  
  1561.  
  1562. static void do_concept_centers_and_ends(
  1563.    setup *ss,
  1564.    parse_block *parseptr,
  1565.    setup *result)
  1566. {
  1567.    int thing;
  1568.    calldef_schema schema;
  1569.  
  1570.    thing = parseptr->concept->value.arg1;
  1571.    if (thing == 2)
  1572.       schema = schema_concentric_6_2;
  1573.    else if (thing == 3)
  1574.       schema = schema_concentric_2_6;
  1575.    else
  1576.       schema = schema_concentric;
  1577.  
  1578.    concentric_move(ss, parseptr->next, parseptr->subsidiary_root, NULLCALLSPEC, NULLCALLSPEC, 0, 0, schema, 0, 0, result);
  1579. }
  1580.  
  1581.  
  1582. static void do_concept_triple_diamonds(
  1583.    setup *ss,
  1584.    parse_block *parseptr,
  1585.    setup *result)
  1586. {
  1587.    if (ss->kind != s_3dmd) fail("Must have a triple diamond setup to do this concept.");
  1588.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  1589.          (*map_lists[sdmd][2])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  1590. }
  1591.  
  1592.  
  1593. static void do_concept_quad_diamonds(
  1594.    setup *ss,
  1595.    parse_block *parseptr,
  1596.    setup *result)
  1597. {
  1598.    if (ss->kind == s_4dmd)
  1599.       divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  1600.             (*map_lists[sdmd][3])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  1601.    else
  1602.       fail("Must have a quadruple diamond setup to do this concept.");
  1603. }
  1604.  
  1605.  
  1606. static void do_concept_ferris(
  1607.    setup *ss,
  1608.    parse_block *parseptr,
  1609.    setup *result)
  1610. {
  1611.    setup temp;
  1612.  
  1613.    temp = *ss;
  1614.    temp.kind = s3x4;
  1615.    clear_people(&temp);
  1616.  
  1617.    if (parseptr->concept->value.arg1) {
  1618.       /* This is "release". */
  1619.  
  1620.       if ((ss->kind != s_qtag) || ((global_tbonetest & 01) != 0))
  1621.          fail("Must have quarter-tag to do this concept.");
  1622.  
  1623.       if (((
  1624.                (ss->people[0].id1 ^ d_south) |
  1625.                (ss->people[1].id1 ^ d_south) |
  1626.                (ss->people[2].id1 ^ d_south) |
  1627.                (ss->people[3].id1 ^ d_north) |
  1628.                (ss->people[4].id1 ^ d_north) |
  1629.                (ss->people[5].id1 ^ d_north) |
  1630.                (ss->people[6].id1 ^ d_north) |
  1631.                (ss->people[7].id1 ^ d_south)
  1632.             ) & d_mask) == 0) {
  1633.          (void) copy_person(&temp, 1, ss, 0);
  1634.          (void) copy_person(&temp, 4, ss, 1);
  1635.          (void) copy_person(&temp, 6, ss, 2);
  1636.          (void) copy_person(&temp, 5, ss, 3);
  1637.          (void) copy_person(&temp, 7, ss, 4);
  1638.          (void) copy_person(&temp, 10, ss, 5);
  1639.          (void) copy_person(&temp, 0, ss, 6);
  1640.          (void) copy_person(&temp, 11, ss, 7);
  1641.       }
  1642.       else if (((
  1643.                (ss->people[0].id1 ^ d_south) |
  1644.                (ss->people[1].id1 ^ d_south) |
  1645.                (ss->people[2].id1 ^ d_north) |
  1646.                (ss->people[3].id1 ^ d_south) |
  1647.                (ss->people[4].id1 ^ d_north) |
  1648.                (ss->people[5].id1 ^ d_north) |
  1649.                (ss->people[6].id1 ^ d_south) |
  1650.                (ss->people[7].id1 ^ d_north)
  1651.             ) & d_mask) == 0) {
  1652.          (void) copy_person(&temp, 10, ss, 0);
  1653.          (void) copy_person(&temp, 2, ss, 1);
  1654.          (void) copy_person(&temp, 3, ss, 2);
  1655.          (void) copy_person(&temp, 5, ss, 3);
  1656.          (void) copy_person(&temp, 4, ss, 4);
  1657.          (void) copy_person(&temp, 8, ss, 5);
  1658.          (void) copy_person(&temp, 9, ss, 6);
  1659.          (void) copy_person(&temp, 11, ss, 7);
  1660.       }
  1661.       else
  1662.          fail("Incorrect facing directions.");
  1663.    }
  1664.    else {
  1665.       /* This is "ferris". */
  1666.  
  1667.       if ((ss->kind != s2x4) || ((global_tbonetest & 01) != 0))
  1668.          fail("Must have lines to do this concept.");
  1669.  
  1670.       if (((
  1671.                (ss->people[0].id1 ^ d_north) |
  1672.                (ss->people[1].id1 ^ d_north) |
  1673.                (ss->people[2].id1 ^ d_south) |
  1674.                (ss->people[3].id1 ^ d_south) |
  1675.                (ss->people[4].id1 ^ d_south) |
  1676.                (ss->people[5].id1 ^ d_south) |
  1677.                (ss->people[6].id1 ^ d_north) |
  1678.                (ss->people[7].id1 ^ d_north)
  1679.             ) & d_mask) == 0) {
  1680.          (void) copy_person(&temp, 0, ss, 0);
  1681.          (void) copy_person(&temp, 1, ss, 1);
  1682.          (void) copy_person(&temp, 5, ss, 2);
  1683.          (void) copy_person(&temp, 4, ss, 3);
  1684.          (void) copy_person(&temp, 6, ss, 4);
  1685.          (void) copy_person(&temp, 7, ss, 5);
  1686.          (void) copy_person(&temp, 11, ss, 6);
  1687.          (void) copy_person(&temp, 10, ss, 7);
  1688.       }
  1689.       else if (((
  1690.                (ss->people[0].id1 ^ d_south) |
  1691.                (ss->people[1].id1 ^ d_south) |
  1692.                (ss->people[2].id1 ^ d_north) |
  1693.                (ss->people[3].id1 ^ d_north) |
  1694.                (ss->people[4].id1 ^ d_north) |
  1695.                (ss->people[5].id1 ^ d_north) |
  1696.                (ss->people[6].id1 ^ d_south) |
  1697.                (ss->people[7].id1 ^ d_south)
  1698.             ) & d_mask) == 0) {
  1699.          (void) copy_person(&temp, 10, ss, 0);
  1700.          (void) copy_person(&temp, 11, ss, 1);
  1701.          (void) copy_person(&temp, 2, ss, 2);
  1702.          (void) copy_person(&temp, 3, ss, 3);
  1703.          (void) copy_person(&temp, 4, ss, 4);
  1704.          (void) copy_person(&temp, 5, ss, 5);
  1705.          (void) copy_person(&temp, 8, ss, 6);
  1706.          (void) copy_person(&temp, 9, ss, 7);
  1707.       }
  1708.       else
  1709.          fail("Incorrect facing directions.");
  1710.    }
  1711.  
  1712.    divided_setup_move(&temp, parseptr->next, NULLCALLSPEC, 0,
  1713.       (*map_lists[s1x4][2])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  1714.  
  1715.    /* Squash phantoms if they are properly placed. */
  1716.  
  1717.    if (result->kind == s2x6) {
  1718.       if (!(result->people[0].id1 | result->people[5].id1 | result->people[6].id1 | result->people[11].id1)) {
  1719.          temp = *result;
  1720.          clear_people(result);
  1721.          (void) copy_person(result, 0, &temp, 1);
  1722.          (void) copy_person(result, 3, &temp, 4);
  1723.          (void) copy_person(result, 4, &temp, 7);
  1724.          (void) copy_person(result, 7, &temp, 10);
  1725.       }
  1726.       else if (!(result->people[1].id1 | result->people[4].id1 | result->people[7].id1 | result->people[10].id1)) {
  1727.          temp = *result;
  1728.          clear_people(result);
  1729.          (void) copy_person(result, 0, &temp, 0);
  1730.          (void) copy_person(result, 3, &temp, 5);
  1731.          (void) copy_person(result, 4, &temp, 6);
  1732.          (void) copy_person(result, 7, &temp, 11);
  1733.       }
  1734.       else
  1735.          return;
  1736.  
  1737.       (void) copy_person(result, 1, &temp, 2);
  1738.       (void) copy_person(result, 2, &temp, 3);
  1739.       (void) copy_person(result, 5, &temp, 8);
  1740.       (void) copy_person(result, 6, &temp, 9);
  1741.  
  1742.       result->kind = s2x4;
  1743.    }
  1744. }
  1745.  
  1746.  
  1747. static void do_concept_meta(
  1748.    setup *ss,
  1749.    parse_block *parseptr,
  1750.    setup *result)
  1751. {
  1752.    final_set new_final_concepts;
  1753.    parse_block *parseptrcopy;
  1754.    parse_block *parseptrcopycopy;
  1755.    int finalsetupflags;
  1756.    unsigned int index;
  1757.  
  1758.    if (ss->setupflags & SETUPFLAG__FRACTIONALIZE_MASK)
  1759.       fail("Can't stack meta or fractional concepts.");
  1760.  
  1761.    /* Scan the "final" concepts, remembering them and their end point. */
  1762.    parseptrcopy = process_final_concepts(parseptr->next, TRUE, &new_final_concepts);
  1763.  
  1764.    /* These are the concepts that we are interested in. */
  1765.  
  1766.    if (parseptrcopy->concept->kind <= marker_end_of_list)
  1767.       fail("Need a real concept here.");
  1768.  
  1769.    if (new_final_concepts) fail("Need a real concept here.");
  1770.  
  1771.    /* Examine the concept.  It must be a real one. */
  1772.  
  1773.    if (concept_table[parseptrcopy->concept->kind].concept_action == 0)
  1774.       fail("Need a real concept here.");
  1775.  
  1776.    if (concept_table[parseptrcopy->concept->kind].concept_prop & CONCPROP__SECOND_CALL)
  1777.       fail("Can't use a concept that takes a second call.");
  1778.  
  1779.    *result = *ss;
  1780.    finalsetupflags = 0;
  1781.  
  1782.    if (parseptr->concept->value.arg1 == 3) {
  1783.       /* Arg1 = 3 is special: we select the first part with the concept, using a
  1784.          fractionalize field of [0 0 1], and then the rest of the call without the
  1785.          concept, using a fractionalize field of [1 0 1]. */
  1786.  
  1787.       setup tttt;
  1788.  
  1789.       tttt = *result;
  1790.       /* Set the fractionalize field to [0 0 1].  This will execute the first part of the call. */
  1791.       tttt.setupflags = ss->setupflags | SETUPFLAG__FRACTIONALIZE_BIT;
  1792.  
  1793.       /* Do the call with the concept. */
  1794.       move(&tttt, parseptrcopy, NULLCALLSPEC, 0, FALSE, result);
  1795.       finalsetupflags |= result->setupflags;
  1796.       normalize_setup(result, simple_normalize);
  1797.  
  1798.       tttt = *result;
  1799.       /* Set the fractionalize field to [1 0 1].  This will execute the rest of the call. */
  1800.       tttt.setupflags = ss->setupflags | (65*SETUPFLAG__FRACTIONALIZE_BIT);
  1801.  
  1802.       /* Do the call without the concept. */
  1803.       move(&tttt, parseptrcopy->next, NULLCALLSPEC, 0, FALSE, result);
  1804.       finalsetupflags |= result->setupflags;
  1805.       normalize_setup(result, simple_normalize);
  1806.    }
  1807.    else {
  1808.       /* Otherwise, this is the "random", "reverse random", or "piecewise" concept.
  1809.          Repeatedly execute parts of the call, using a fractionalize field of [2 0 index],
  1810.          and skipping the concept where required. */
  1811.    
  1812.       index = 0;
  1813.  
  1814.       do {
  1815.          setup tttt;
  1816.      
  1817.          tttt = *result;
  1818.          index++;
  1819.          /* Set the fractionalize field to [2 0 index]. */
  1820.          tttt.setupflags = ss->setupflags | ((128|index)*SETUPFLAG__FRACTIONALIZE_BIT);
  1821.          parseptrcopycopy = parseptrcopy;
  1822.          /* If concept is "[reverse] random" and this is an even/odd-numbered part,
  1823.             as the case may be, skip over the concept. */
  1824.          if (((parseptr->concept->value.arg1 & ~1) == 0) &&
  1825.                ((index & 1) == parseptr->concept->value.arg1)) {
  1826.             /* Need to skip the concept.  Note that we have already forbidden
  1827.                concepts that take another call. */
  1828.             parseptrcopycopy = parseptrcopycopy->next;
  1829.          }
  1830.      
  1831.          move(&tttt, parseptrcopycopy, NULLCALLSPEC, 0, FALSE, result);
  1832.          finalsetupflags |= result->setupflags;
  1833.          normalize_setup(result, simple_normalize);
  1834.       }
  1835.       while (!(result->setupflags & RESULTFLAG__DID_LAST_PART));
  1836.    }
  1837.   
  1838.    result->setupflags = finalsetupflags & ~RESULTFLAG__ELONGATE_MASK;
  1839. }
  1840.  
  1841.  
  1842. static void do_concept_nth_part(
  1843.    setup *ss,
  1844.    parse_block *parseptr,
  1845.    setup *result)
  1846. {
  1847.    final_set new_final_concepts;
  1848.    parse_block *parseptrcopy;
  1849.    setup tttt;
  1850.    int finalsetupflags;
  1851.  
  1852.    if (ss->setupflags & SETUPFLAG__FRACTIONALIZE_MASK)
  1853.       fail("Can't stack meta or fractional concepts.");
  1854.  
  1855.    /* Scan the "final" concepts, remembering them and their end point. */
  1856.    parseptrcopy = process_final_concepts(parseptr->next, TRUE, &new_final_concepts);
  1857.  
  1858.    /* These are the concepts that we are interested in. */
  1859.  
  1860.    if (parseptrcopy->concept->kind <= marker_end_of_list)
  1861.       fail("Need a real concept here.");
  1862.  
  1863.    if (new_final_concepts) fail("Need a real concept here.");
  1864.  
  1865.    /* Examine the concept.  It must be a real one. */
  1866.  
  1867.    if (concept_table[parseptrcopy->concept->kind].concept_action == 0)
  1868.       fail("Need a real concept here.");
  1869.  
  1870.    if (concept_table[parseptrcopy->concept->kind].concept_prop & CONCPROP__SECOND_CALL)
  1871.       fail("Can't use a concept that takes a second call.");
  1872.  
  1873.    *result = *ss;
  1874.    finalsetupflags = 0;
  1875.  
  1876.    /* Do the initial part, if any. */
  1877.  
  1878.    if (parseptr->number > 1) {
  1879.       tttt = *result;
  1880.       /* Set the fractionalize field to [0 0 parts-to-do-normally]. */
  1881.       tttt.setupflags = ss->setupflags | ((parseptr->number-1)*SETUPFLAG__FRACTIONALIZE_BIT);
  1882.       /* Skip over the concept. */
  1883.       move(&tttt, parseptrcopy->next, NULLCALLSPEC, 0, FALSE, result);
  1884.       finalsetupflags |= result->setupflags;
  1885.       normalize_setup(result, simple_normalize);
  1886.    }
  1887.  
  1888.    /* Do the part of the call that needs the concept. */
  1889.  
  1890.    tttt = *result;
  1891.    /* Set the fractionalize field to [2 0 part-to-do-with-concept]. */
  1892.    tttt.setupflags = ss->setupflags | ((128|parseptr->number)*SETUPFLAG__FRACTIONALIZE_BIT);
  1893.    /* Do the concept. */
  1894.    move(&tttt, parseptrcopy, NULLCALLSPEC, 0, FALSE, result);
  1895.    finalsetupflags |= result->setupflags;
  1896.    normalize_setup(result, simple_normalize);
  1897.  
  1898.    /* Do the final part, if there is more. */
  1899.  
  1900.    if (!(result->setupflags & RESULTFLAG__DID_LAST_PART)) {
  1901.       tttt = *result;
  1902.       /* Set the fractionalize field to [1 0 parts-to-do-normally+1]. */
  1903.       tttt.setupflags = ss->setupflags | ((64|parseptr->number)*SETUPFLAG__FRACTIONALIZE_BIT);
  1904.       /* Skip over the concept. */
  1905.       move(&tttt, parseptrcopy->next, NULLCALLSPEC, 0, FALSE, result);
  1906.       finalsetupflags |= result->setupflags;
  1907.       normalize_setup(result, simple_normalize);
  1908.    }
  1909.  
  1910.    result->setupflags = finalsetupflags & ~RESULTFLAG__ELONGATE_MASK;
  1911. }
  1912.  
  1913.  
  1914. static void do_concept_replace_nth_part(
  1915.    setup *ss,
  1916.    parse_block *parseptr,
  1917.    setup *result)
  1918. {
  1919.    setup tttt;
  1920.    int finalsetupflags;
  1921.    int stopindex;
  1922.  
  1923.    *result = *ss;
  1924.    finalsetupflags = 0;
  1925.  
  1926.    /* Do the initial part, if any. */
  1927.  
  1928.    if (parseptr->concept->value.arg1)
  1929.       stopindex = parseptr->number;      /* Interrupt after Nth part. */
  1930.    else
  1931.       stopindex = parseptr->number-1;    /* Replace Nth part. */
  1932.  
  1933.    if (stopindex > 0) {
  1934.       tttt = *result;
  1935.       /* Set the fractionalize field to [0 0 parts-to-do-normally]. */
  1936.       tttt.setupflags = ss->setupflags | ((stopindex)*SETUPFLAG__FRACTIONALIZE_BIT);
  1937.       /* Skip over the concept. */
  1938.       move(&tttt, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1939.       finalsetupflags |= result->setupflags;
  1940.       normalize_setup(result, simple_normalize);
  1941.    }
  1942.  
  1943.    /* Do the interruption/replacement call. */
  1944.  
  1945.    tttt = *result;
  1946.    tttt.setupflags = ss->setupflags;
  1947.    update_id_bits(&tttt);           /* So you can interrupt with "leads run", etc. */
  1948.    move(&tttt, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  1949.    finalsetupflags |= result->setupflags;
  1950.    normalize_setup(result, simple_normalize);
  1951.  
  1952.    /* Do the final part, if there is more. */
  1953.  
  1954.    tttt = *result;
  1955.    /* Set the fractionalize field to [1 0 parts-to-do-normally+1]. */
  1956.    tttt.setupflags = ss->setupflags | ((64|parseptr->number)*SETUPFLAG__FRACTIONALIZE_BIT);
  1957.    /* Skip over the concept. */
  1958.    move(&tttt, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1959.    finalsetupflags |= result->setupflags;
  1960.    normalize_setup(result, simple_normalize);
  1961.  
  1962.    result->setupflags = finalsetupflags & ~RESULTFLAG__ELONGATE_MASK;
  1963. }
  1964.  
  1965.  
  1966. static void do_concept_interlace(
  1967.    setup *ss,
  1968.    parse_block *parseptr,
  1969.    setup *result)
  1970. {
  1971.    int finalsetupflags;
  1972.    unsigned int index;
  1973.    long_boolean first_active, second_active;
  1974.  
  1975.    finalsetupflags = 0;
  1976.    first_active = TRUE;
  1977.    second_active = TRUE;
  1978.    index = 0;
  1979.  
  1980.    if (ss->setupflags & SETUPFLAG__FRACTIONALIZE_MASK)
  1981.       fail("Can't stack meta or fractional concepts.");
  1982.  
  1983.    *result = *ss;
  1984.  
  1985.    do {
  1986.       setup tttt;
  1987.  
  1988.       index++;
  1989.  
  1990.       if (first_active) {
  1991.          tttt = *result;
  1992.          /* Set the fractionalize field to [2 0 index]. */
  1993.          tttt.setupflags = ss->setupflags | ((128|index)*SETUPFLAG__FRACTIONALIZE_BIT);
  1994.      
  1995.          /* Do the indicated part of the first call. */
  1996.          move(&tttt, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  1997.          finalsetupflags |= result->setupflags;
  1998.          normalize_setup(result, simple_normalize);
  1999.          first_active = !(result->setupflags & RESULTFLAG__DID_LAST_PART);
  2000.       }
  2001.  
  2002.       if (second_active) {
  2003.          tttt = *result;
  2004.          /* Set the fractionalize field to [2 0 index]. */
  2005.          tttt.setupflags = ss->setupflags | ((128|index)*SETUPFLAG__FRACTIONALIZE_BIT);
  2006.      
  2007.          /* Do the indicated part of the second call. */
  2008.          move(&tttt, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  2009.          finalsetupflags |= result->setupflags;
  2010.          normalize_setup(result, simple_normalize);
  2011.          second_active = !(result->setupflags & RESULTFLAG__DID_LAST_PART);
  2012.       }
  2013.    }
  2014.    while (first_active || second_active);
  2015.   
  2016.    result->setupflags = finalsetupflags & ~RESULTFLAG__ELONGATE_MASK;
  2017. }
  2018.  
  2019.  
  2020. static void do_concept_fractional(
  2021.    setup *ss,
  2022.    parse_block *parseptr,
  2023.    setup *result)
  2024. {
  2025.    /* Note: if we ever implement something that omits the first fraction, that
  2026.       concept would have to have "CONCPROP__NO_STEP" set in concept_table, and
  2027.       things might get ugly. */
  2028.    int numer, denom;
  2029.  
  2030.    if (ss->setupflags & SETUPFLAG__FRACTIONALIZE_MASK)
  2031.       fail("Can't stack meta or fractional concepts.");
  2032.  
  2033.    numer = parseptr->number;
  2034.    denom = numer >> 16;
  2035.    numer &= 0xFFFF;
  2036.    /* Set the fractionalize field to [0 denominator numerator]. */
  2037.    ss->setupflags |= ((denom*8) | numer)*SETUPFLAG__FRACTIONALIZE_BIT;
  2038.  
  2039.    move(ss, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  2040. }
  2041.  
  2042.  
  2043. static void do_concept_so_and_so_begin(
  2044.    setup *ss,
  2045.    parse_block *parseptr,
  2046.    setup *result)
  2047. {
  2048.    int finalsetupflags;
  2049.    selector_kind saved_selector;
  2050.    int i;
  2051.    setup setup1, setup2, res1;
  2052.  
  2053.    if (ss->setupflags & SETUPFLAG__FRACTIONALIZE_MASK)
  2054.       fail("Can't stack meta or fractional concepts.");
  2055.  
  2056.    saved_selector = current_selector;
  2057.    current_selector = parseptr->selector;
  2058.  
  2059.    setup1 = *ss;              /* designees */
  2060.    setup2 = *ss;              /* non-designees */
  2061.    
  2062.    if (setup_limits[ss->kind] < 0) fail("Can't identify people in this setup.");
  2063.    for (i=0; i<setup_limits[ss->kind]+1; i++) {
  2064.       if (ss->people[i].id1) {
  2065.          if (selectp(ss, i))
  2066.             clear_person(&setup2, i);
  2067.          else
  2068.             clear_person(&setup1, i);
  2069.       }
  2070.    }
  2071.    
  2072.    current_selector = saved_selector;
  2073.    
  2074.    normalize_setup(&setup1, normalize_before_isolated_call);
  2075.    normalize_setup(&setup2, normalize_before_isolated_call);
  2076.    /* Set the fractionalize field to [0 0 1].  This will execute the first part of the call. */
  2077.    setup1.setupflags = ss->setupflags | SETUPFLAG__FRACTIONALIZE_BIT;
  2078.  
  2079.    /* The selected people execute the first part of the call. */
  2080.  
  2081.    move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  2082.    setup2.setupflags = res1.setupflags;
  2083.    merge_setups(&res1, &setup2);
  2084.    finalsetupflags = setup2.setupflags;
  2085.    normalize_setup(&setup2, simple_normalize);
  2086.  
  2087.    /* Set the fractionalize field to [1 0 1].  This will execute the rest of the call. */
  2088.    setup2.setupflags = ss->setupflags | (65*SETUPFLAG__FRACTIONALIZE_BIT);
  2089.  
  2090.    /* Everyone executes the second part of the call. */
  2091.    move(&setup2, parseptr->next, NULLCALLSPEC, 0, FALSE, result);
  2092.    finalsetupflags |= result->setupflags;
  2093.    normalize_setup(result, simple_normalize);
  2094.   
  2095.    result->setupflags = finalsetupflags & ~RESULTFLAG__ELONGATE_MASK;
  2096. }
  2097.  
  2098.  
  2099. static void do_concept_misc_distort(
  2100.    setup *ss,
  2101.    parse_block *parseptr,
  2102.    setup *result)
  2103. {
  2104.    distorted_2x2s_move(ss, parseptr, result);
  2105.    reinstate_rotation(ss, result);
  2106. }
  2107.  
  2108.  
  2109. static void do_concept_do_phantom_2x4(
  2110.    setup *ss,
  2111.    parse_block *parseptr,
  2112.    setup *result)
  2113. {
  2114.  
  2115.    /* This concept is "standard", which means that it can look at global_tbonetest
  2116.       and global_livemask, but may not look at anyone's facing direction other
  2117.       than through global_tbonetest. */
  2118.  
  2119.    if (ss->kind != s4x4) fail("Need a 4x4 setup to do this concept.");
  2120.  
  2121.    /* If not T-boned, we can do something glorious. */
  2122.  
  2123.    if ((global_tbonetest & 011) != 011) {
  2124.       int rot;
  2125.       
  2126.       rot = (global_tbonetest ^ parseptr->concept->value.arg2) & 1;
  2127.       ss->rotation += rot;   /* Just flip the setup around and recanonicalize. */
  2128.       canonicalize_rotation(ss);
  2129.       divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0, parseptr->concept->value.maps,
  2130.             (phantest_kind) parseptr->concept->value.arg1, TRUE, result);
  2131.       result->rotation -= rot;   /* Flip the setup back. */
  2132.       return;
  2133.    }
  2134.  
  2135.    /* People are T-boned!  This is messy. */
  2136.  
  2137.    phantom_2x4_move(
  2138.       ss,
  2139.       parseptr->concept->value.arg2,
  2140.       (phantest_kind) parseptr->concept->value.arg1,
  2141.       parseptr->concept->value.maps,
  2142.       parseptr->next,
  2143.       result);
  2144. }
  2145.  
  2146.  
  2147. static void do_concept_concentric(
  2148.    setup *ss,
  2149.    parse_block *parseptr,
  2150.    setup *result)
  2151. {
  2152.    concentric_move(ss, parseptr->next, parseptr->next, NULLCALLSPEC, NULLCALLSPEC, 0, 0,
  2153.          (calldef_schema) parseptr->concept->value.arg1, 0, dfm_conc_concentric_rules, result);
  2154. }
  2155.  
  2156.  
  2157. static void do_concept_single_concentric(
  2158.    setup *ss,
  2159.    parse_block *parseptr,
  2160.    setup *result)
  2161. {
  2162.    switch (ss->kind) {
  2163.       case s2x4:
  2164.          divided_setup_move(ss, parseptr, NULLCALLSPEC, 0, (*map_lists[s1x4][1])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  2165.          break;
  2166.       case s1x8:
  2167.          divided_setup_move(ss, parseptr, NULLCALLSPEC, 0, (*map_lists[s1x4][1])[MPKIND__SPLIT][0], phantest_ok, TRUE, result);
  2168.          break;
  2169.       case s_qtag:
  2170.          divided_setup_move(ss, parseptr, NULLCALLSPEC, 0, (*map_lists[sdmd][1])[MPKIND__SPLIT][1], phantest_ok, TRUE, result);
  2171.          break;
  2172.       case s_ptpd:
  2173.          divided_setup_move(ss, parseptr, NULLCALLSPEC, 0, (*map_lists[sdmd][1])[MPKIND__SPLIT][0], phantest_ok, TRUE, result);
  2174.          break;
  2175.       case s1x4: case sdmd:
  2176.          concentric_move(ss, parseptr->next, parseptr->next, NULLCALLSPEC, NULLCALLSPEC, 0, 0,
  2177.                (calldef_schema) parseptr->concept->value.arg1, 0, dfm_conc_concentric_rules, result);
  2178.          break;
  2179.       default:
  2180.          fail("Can't figure out how to do single concentric here.");
  2181.    }
  2182. }
  2183.  
  2184.  
  2185. static void do_concept_tandem(
  2186.    setup *ss,
  2187.    parse_block *parseptr,
  2188.    setup *result)
  2189. {
  2190.    tandem_couples_move(ss, parseptr->next, NULLCALLSPEC, 0,
  2191.          parseptr->concept->value.arg1 ? parseptr->selector : selector_uninitialized,
  2192.          parseptr->concept->value.arg2,    /* normal=FALSE, twosome=TRUE */
  2193.          parseptr->concept->value.arg3,    /* normal=0 phantom=1 gruesome=2 */
  2194.          parseptr->concept->value.arg4,    /* couples=0 tandem=1 siamese=2 */
  2195.          result);
  2196. }
  2197.  
  2198.  
  2199. static void do_concept_standard(
  2200.    setup *ss,
  2201.    parse_block *parseptr,
  2202.    setup *result)
  2203. {
  2204.    parse_block *parseptrcopy;
  2205.    int tbonetest, stdtest, livemask;
  2206.  
  2207.    tbonetest = 0;
  2208.    stdtest = 0;
  2209.    livemask = 0;
  2210.  
  2211.    if (setup_limits[ss->kind] < 0) fail("Can't do this concept in this setup.");
  2212.  
  2213.    {
  2214.       selector_kind saved_selector;
  2215.       int i, j;
  2216.  
  2217.       saved_selector = current_selector;
  2218.       current_selector = parseptr->selector;
  2219.  
  2220.       for (i=0, j=1; i<=setup_limits[ss->kind]; i++, j<<=1) {
  2221.          int p = ss->people[i].id1;
  2222.          tbonetest |= p;
  2223.          if (p) {
  2224.             livemask |= j;
  2225.             if (selectp(ss, i)) stdtest |= p;
  2226.          }
  2227.       }
  2228.  
  2229.       current_selector = saved_selector;
  2230.    }
  2231.  
  2232.    if (!tbonetest) {
  2233.       result->kind = nothing;
  2234.       return;
  2235.    }
  2236.  
  2237.    if ((tbonetest & 011) != 011) fail("People are not T-boned -- 'standard' is meaningless.");
  2238.  
  2239.    if (!stdtest) fail("No one is standard.");
  2240.    if ((stdtest & 011) == 011) fail("The standard people are not facing consistently.");
  2241.  
  2242.    global_tbonetest = stdtest;
  2243.    global_livemask = livemask;
  2244.  
  2245.    parseptrcopy = parseptr->next;       /* should point to the phantom-line (or whatever) concept. */
  2246.  
  2247.    while (parseptrcopy->concept->kind == concept_comment) parseptrcopy = parseptrcopy->next;
  2248.  
  2249.    if (concept_table[parseptrcopy->concept->kind].concept_prop & CONCPROP__STANDARD) {
  2250.       (concept_table[parseptrcopy->concept->kind].concept_action)(ss, parseptrcopy, result);
  2251.    }
  2252.    else {
  2253.       fail("This concept must be used with some offset/distorted/phantom concept.");
  2254.    }
  2255. }
  2256.  
  2257.  
  2258. extern long_boolean do_big_concept(
  2259.    setup *ss,
  2260.    parse_block *parseptr,
  2261.    setup *result)
  2262. {
  2263.    void (*concept_func)(setup *, parse_block *, setup *);
  2264.  
  2265.    concept_func = concept_table[parseptr->concept->kind].concept_action;
  2266.  
  2267.    if (concept_func == 0) return(FALSE);
  2268.  
  2269.    if (concept_table[parseptr->concept->kind].concept_prop & CONCPROP__SET_PHANTOMS)
  2270.       ss->setupflags |= SETUPFLAG__PHANTOMS;
  2271.  
  2272.    if (concept_table[parseptr->concept->kind].concept_prop & CONCPROP__NO_STEP)
  2273.       ss->setupflags |= SETUPFLAG__NO_STEP_TO_WAVE;
  2274.  
  2275.    clear_people(result);
  2276.    result->setupflags = 0;
  2277.  
  2278.    /* See if this concept can be invoked with "standard".  If so, it wants
  2279.       tbonetest and livemask computed, and expects the former to indicate
  2280.       only the standard people. */
  2281.  
  2282.    if (concept_table[parseptr->concept->kind].concept_prop & (CONCPROP__STANDARD | CONCPROP__GET_MASK)) {
  2283.       int i, j;
  2284.       long_boolean doing_select;
  2285.       selector_kind saved_selector;
  2286.  
  2287.       if (setup_limits[ss->kind] < 0) fail("Can't do this concept in this setup.");
  2288.  
  2289.       global_tbonetest = 0;
  2290.       global_livemask = 0;
  2291.       global_selectmask = 0;
  2292.       doing_select = concept_table[parseptr->concept->kind].concept_prop & CONCPROP__USE_SELECTOR;
  2293.  
  2294.       if (doing_select) {
  2295.          saved_selector = current_selector;
  2296.          current_selector = parseptr->selector;
  2297.       }
  2298.  
  2299.       for (i=0, j=1; i<=setup_limits[ss->kind]; i++, j<<=1) {
  2300.          int p = ss->people[i].id1;
  2301.          global_tbonetest |= p;
  2302.          if (p) {
  2303.             global_livemask |= j;
  2304.             if (doing_select && selectp(ss, i)) global_selectmask |= j;
  2305.          }
  2306.       }
  2307.  
  2308.       if (doing_select)
  2309.          current_selector = saved_selector;
  2310.  
  2311.       if (!global_tbonetest) result->kind = nothing;
  2312.       else
  2313.          (*concept_func)(ss, parseptr, result);
  2314.    }
  2315.    else {
  2316.       (*concept_func)(ss, parseptr, result);
  2317.    }
  2318.  
  2319.    canonicalize_rotation(result);
  2320.    return(TRUE);
  2321. }
  2322.  
  2323.  
  2324. /* Beware!!  This table must be keyed to definition of "concept_kind" in sd.h . */
  2325.  
  2326. concept_table_item concept_table[] = {
  2327.    {0,                                                                                      0},                               /* concept_another_call_next_mod */
  2328.    {0,                                                                                      0},                               /* concept_another_call_next_modreact */
  2329.    {0,                                                                                      0},                               /* concept_another_call_next_modtag */
  2330.    {0,                                                                                      0},                               /* concept_another_call_next_force */
  2331.    {0,                                                                                      0},                               /* concept_mod_declined */
  2332.    {0,                                                                                      0},                               /* marker_end_of_list */
  2333.    {0,                                                                                      0},                               /* concept_comment */
  2334.    {0,                                                                                      do_concept_concentric},           /* concept_concentric */
  2335.    {0,                                                                                      do_concept_single_concentric},    /* concept_single_concentric */
  2336.    {0,                                                                                      do_concept_tandem},               /* concept_tandem */
  2337.    {CONCPROP__NEED_4X4 | CONCPROP__SET_PHANTOMS,                                            do_concept_tandem},               /* concept_phantom_tandem */
  2338.    {CONCPROP__NEED_2X8 | CONCPROP__SET_PHANTOMS,                                            do_concept_tandem},               /* concept_gruesome_tandem */
  2339.    {CONCPROP__USE_SELECTOR,                                                                 do_concept_tandem},               /* concept_some_are_tandem */
  2340.    {0,                                                                                      do_concept_checkerboard},         /* concept_checkerboard */
  2341.    {0,                                                                                      0},                               /* concept_reverse */
  2342.    {0,                                                                                      0},                               /* concept_left */
  2343.    {0,                                                                                      0},                               /* concept_grand */
  2344.    {0,                                                                                      0},                               /* concept_magic */
  2345.    {0,                                                                                      0},                               /* concept_cross */
  2346.    {0,                                                                                      0},                               /* concept_singlefile */
  2347.    {0,                                                                                      0},                               /* concept_interlocked */
  2348.    {0,                                                                                      0},                               /* concept_12_matrix */
  2349.    {0,                                                                                      0},                               /* concept_funny */
  2350.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK,                                                 triangle_move},                   /* concept_randomtrngl */
  2351.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK | CONCPROP__USE_SELECTOR,                        triangle_move},                   /* concept_selbasedtrngl */
  2352.    {0,                                                                                      0},                               /* concept_split */
  2353.    {0,                                                                                      0},                               /* concept_diamond */
  2354.    {0,                                                                                      0},                               /* concept_triangle */
  2355.    {CONCPROP__NO_STEP,                                                                      do_concept_do_both_boxes},        /* concept_do_both_boxes */
  2356.    {0,                                                                                      do_concept_once_removed},         /* concept_once_removed */
  2357.    {CONCPROP__NEED_4X4 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_do_phantom_2x2},       /* concept_do_phantom_2x2 */
  2358.    {CONCPROP__NEED_2X8 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_do_phantom_boxes},     /* concept_do_phantom_boxes */
  2359.    {CONCPROP__NEED_4DMD | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                       do_concept_do_phantom_diamonds},  /* concept_do_phantom_diamonds */
  2360.    {CONCPROP__NEED_2X6 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_do_phantom_1x6},       /* concept_do_phantom_1x6 */
  2361.    {CONCPROP__NEED_2X8 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_do_phantom_1x8},       /* concept_do_phantom_1x8 */
  2362.    {CONCPROP__NEED_4X4 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_do_phantom_2x4},       /* concept_do_phantom_2x4 */
  2363.    {CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,                        do_concept_do_phantom_2x3},       /* concept_do_phantom_2x3 */
  2364.    {CONCPROP__NEED_2X8 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_divided_2x4},          /* concept_divided_2x4 */
  2365.    {CONCPROP__NEED_2X6 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_divided_2x3},          /* concept_divided_2x3 */
  2366.    {CONCPROP__NO_STEP | CONCPROP__STANDARD,                                                 distorted_move},                  /* concept_distorted */
  2367.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK | CONCPROP__USE_SELECTOR,                        do_concept_single_diagonal},      /* concept_single_diagonal */
  2368.    {CONCPROP__NO_STEP | CONCPROP__STANDARD,                                                 do_concept_double_diagonal},      /* concept_double_diagonal */
  2369.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK,                                                 do_concept_parallelogram},        /* concept_parallelogram */
  2370.    {CONCPROP__SET_PHANTOMS | CONCPROP__STANDARD,                                            do_concept_triple_lines},         /* concept_triple_lines */
  2371.    {CONCPROP__SET_PHANTOMS,                                                                 do_concept_triple_lines_tog},     /* concept_triple_lines_together */
  2372.    {CONCPROP__NEED_4X4 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   do_concept_quad_lines},           /* concept_quad_lines */
  2373.    {CONCPROP__NEED_4X4 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_quad_lines_tog},       /* concept_quad_lines_together */
  2374.    {CONCPROP__NEED_2X8 | CONCPROP__NO_STEP,                                                 do_concept_quad_boxes},           /* concept_quad_boxes */
  2375.    {CONCPROP__NEED_2X8 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_quad_boxes_tog},       /* concept_quad_boxes_together */
  2376.    {CONCPROP__NEED_2X6 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_triple_boxes},         /* concept_triple_boxes */
  2377.    {CONCPROP__NEED_2X6 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                        do_concept_triple_boxes_tog},     /* concept_triple_boxes_together */
  2378.    {CONCPROP__NEED_3DMD | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                       do_concept_triple_diamonds},      /* concept_triple_diamonds */
  2379.    {CONCPROP__NEED_3DMD | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                       do_concept_triple_diamonds_tog},  /* concept_triple_diamonds_together */
  2380.    {CONCPROP__NEED_4DMD | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                       do_concept_quad_diamonds},        /* concept_quad_diamonds */
  2381.    {CONCPROP__NEED_4DMD | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP,                       do_concept_quad_diamonds_tog},    /* concept_quad_diamonds_together */
  2382.    {CONCPROP__NEED_BLOB | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,  do_concept_triple_diag},          /* concept_triple_diag */
  2383.    {CONCPROP__NEED_BLOB | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__GET_MASK,  do_concept_triple_diag_tog},      /* concept_triple_diag_together */
  2384.    {CONCPROP__NEED_4X6 | CONCPROP__SET_PHANTOMS | CONCPROP__NO_STEP | CONCPROP__STANDARD,   triple_twin_move},                /* concept_triple_twin */
  2385.    {CONCPROP__NO_STEP,                                                                      do_concept_misc_distort},         /* concept_misc_distort */
  2386.    {CONCPROP__NO_STEP,                                                                      do_concept_old_stretch},          /* concept_old_stretch */
  2387.    {CONCPROP__NO_STEP,                                                                      do_concept_new_stretch},          /* concept_new_stretch */
  2388.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK,                                                 do_c1_phantom_move},              /* concept_c1_phantom */
  2389.    {CONCPROP__NO_STEP,                                                                      do_concept_grand_working},        /* concept_grand_working */
  2390.    {0,                                                                                      do_concept_centers_or_ends},      /* concept_centers_or_ends */
  2391.    {CONCPROP__USE_SELECTOR | CONCPROP__NO_STEP,                                             so_and_so_only_move},             /* concept_so_and_so_only */
  2392.    {CONCPROP__USE_SELECTOR | CONCPROP__SECOND_CALL | CONCPROP__NO_STEP,                     so_and_so_only_move},             /* concept_some_vs_others */
  2393.    {CONCPROP__NO_STEP,                                                                      do_concept_stable},               /* concept_stable */
  2394.    {CONCPROP__USE_SELECTOR | CONCPROP__NO_STEP,                                             do_concept_stable},               /* concept_so_and_so_stable */
  2395.    {CONCPROP__USE_SELECTOR | CONCPROP__NO_STEP,                                             do_concept_standard},             /* concept_standard */
  2396.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK | CONCPROP__USE_SELECTOR,                        do_concept_double_offset},        /* concept_double_offset */
  2397.    {CONCPROP__SECOND_CALL,                                                                  do_concept_checkpoint},           /* concept_checkpoint */
  2398.    {CONCPROP__SECOND_CALL | CONCPROP__NO_STEP,                                              on_your_own_move},                /* concept_on_your_own */
  2399.    {CONCPROP__SECOND_CALL | CONCPROP__NO_STEP,                                              do_concept_trace},                /* concept_trace */
  2400.    {CONCPROP__NO_STEP | CONCPROP__GET_MASK,                                                 do_concept_ferris},               /* concept_ferris */
  2401.    {CONCPROP__SECOND_CALL,                                                                  do_concept_centers_and_ends},     /* concept_centers_and_ends */
  2402.    {CONCPROP__SECOND_CALL,                                                                  do_concept_sequential},           /* concept_sequential */
  2403.    {0,                                                                                      do_concept_meta},                 /* concept_meta */
  2404.    {CONCPROP__USE_SELECTOR,                                                                 do_concept_so_and_so_begin},      /* concept_so_and_so_begin */
  2405.    {CONCPROP__USE_NUMBER,                                                                   do_concept_nth_part},             /* concept_nth_part */
  2406.    {CONCPROP__USE_NUMBER | CONCPROP__SECOND_CALL,                                           do_concept_replace_nth_part},     /* concept_replace_nth_part */
  2407.    {CONCPROP__SECOND_CALL,                                                                  do_concept_interlace},            /* concept_interlace */
  2408.    {CONCPROP__USE_NUMBER | CONCPROP__USE_TWO_NUMBERS,                                       do_concept_fractional},           /* concept_fractional */
  2409.    {CONCPROP__NO_STEP,                                                                      do_concept_rigger},               /* concept_rigger */
  2410.    {CONCPROP__SECOND_CALL | CONCPROP__NO_STEP,                                              do_concept_callrigger}};          /* concept_callrigger */
  2411.